ActiveRecord vs. FormModel

Poste mal den view code mit dem formular sonst ist das pures Rätselraten :)


<div class="form">


<?php $form=$this->beginWidget('CActiveForm', array(

    'id'=>'activity-form',

    'enableAjaxValidation'=>true,

)); 

//I have enableAjaxValidation set to true so i can validate on the fly the

?>


	<p class="note">Fields with <span class="required">*</span> are required.</p>


	<?php echo $form->errorSummary($model); ?>

	


	<fieldset>

	<legend>Allgemeine Informationen</legend>

	

		<div class="row">

			<?php echo $form->labelEx($model,'Abteilung_id'); ?>

			<?php /*echo $form->textField($model,'Ort_plz'); */?>

			<?php echo $form->dropDownList($model,'Abteilung_id', CHtml::listData(Department::model()->findAll(), 'id', 'name'), array('prompt' => Yii::t('buttons','select department'))); ?>

			<?php echo $form->error($model,'Abteilung_id'); ?>

		</div>

		

		<div class="row">

			<?php echo $form->labelEx($model,'Sponsor_id'); ?>

			<?php /*echo $form->textField($model,'Ort_plz'); */?>

			<?php echo $form->dropDownList($model,'Sponsor_id', CHtml::listData(Sponsor::model()->findAll(),'id', 'firmenname'), array('prompt' => Yii::t('buttons','select sponsor'))); ?>

			<?php echo $form->error($model,'Sponsor_id'); ?>

		</div>

		

	</fieldset>

	

	<fieldset>

		

		<div class="row">

			<?php echo $form->labelEx($model,'Leistung_id'); ?>

			<?php echo $form->dropDownList($model,'Leistung_id', CHtml::listData(Service::model()->findAll(),'id', 'name'), array('prompt' => Yii::t('buttons','select service'))); ?>

			<?php echo $form->error($model,'Leistung_id'); ?>

		</div>

		

		<?php echo CHtml::ajaxLink(Yii::t('service','Create Service'),$this->createUrl('service/create'),array(

		        'onclick'=>'$("#serviceDialog").dialog("open"); return false;',

		        'update'=>'#serviceDialog'

		        ),array('id'=>'showServiceDialog'));?>

		    <div id="serviceDialog"></div>

		    

	</fieldset>

	

	<fieldset>

		<div class="row">

			<?php echo $form->labelEx($entry,'preis'); ?>

			<?php echo $form->textField($entry,'preis'); ?>

			<?php echo $form->error($entry,'preis'); ?>

		</div>

		

		<div class="row">

			<?php echo $form->labelEx($entry,'kosten'); ?>

			<?php echo $form->textField($entry,'kosten'); ?>

			<?php echo $form->error($entry,'kosten'); ?>

		</div>

	

		<div class="row">

			<?php echo $form->labelEx($entry,'bemerkung'); ?>

			<?php echo $form->textArea($entry,'bemerkung'); ?>

			<?php echo $form->error($entry,'bemerkung'); ?>

		</div>

	</fieldset>


	<div class="row buttons">

		<?php echo CHtml::submitButton($model->isNewRecord ? Yii::t('buttons','create') : Yii::t('buttons','save')); ?>

	</div>


<?php $this->endWidget(); ?>


</div><!-- form -->

Poste bitte auch noch den Controller Code. Das Formular selbst sieht nämlich ok aus.

Da habe ich diese beiden Methoden:




/**

	 * Creates a new model.

	 * If creation is successful, the browser will be redirected to the 'view' page.

	 */

	public function actionCreate() {

	

		$this->forward('update');

		

	} 


	/**

	 * Updates a particular model.

	 * If update is successful, the browser will be redirected to the 'view' page.

	 * @param integer $id the ID of the model to be updated

	 */

	public function actionUpdate($id = null)

	{

		$model = $id ? Activity::model()->findByPk($id) : new Activity();

				

		$entry = new AEntry;

		

		if (Yii::app()->request->getPost('Activity')) {

			$model->attributes = Yii::app()->request->getPost('Activity');

			if ($model->save()) {

				$entry->attributes = Yii::app()->request->getPost('AEntry');

				$entry->Aktivitaet_id = $model->id;

				if ($entry->save()) {

					$this->redirect($this->createUrl('activity/index'));

				}

			}

		} 


		$this->render('create',array(

			'model'=>$model,

			'entry'=>$entry

		));

	}



und diese hier noch:


/**

	 * Performs the AJAX validation.

	 * @param CModel the model to be validated

	 */

	protected function performAjaxValidation($model)

	{

		if(isset($_POST['ajax']) && $_POST['ajax']==='activity-form')

		{

			echo CActiveForm::validate($model);

			Yii::app()->end();

		}

	}

Hi,

Da sind gleich mehrere Dinge die mir auffallen:

  1. Warum leitet die "create" Methode an die "update" Methode weiter und diese übernimmt dann auch noch die Logik der create action? Das ist ja erstens verwirrend und zweitens sind da Fehler vorprogrammiert. Die create methode tut zwar fast das selbe wie die update methode, trotzdem sollten beide immer eigenständig sein, sonst bringst du dich in Teufels Küche.

  2. Du hattest ja erwähnt, dass modelB nicht ohne modelA erstellt werden kann. Hier nutzt du aber keine Transactions bzw. validierst nicht richtig. Wenn also die Activity Felder alle ausgefüllt werden gibt $model->save() true zurück und legt die activity in der db ab. Wenn jetzt aber das Entry model nicht gespeichert werden kann bleibt die Activity trotzdem in der db, es sollte aber im Endeffekt gar nichts passieren. Also eher sowas hier:




if($model->validate && $entry->validate)

{

   //lege beide in db ab (am besten du verwendest aber auch gleich transactions via try catch blocks, sollte etwas schiefgehen)

   $model->save(),

   $entry->activity_id=$model->id;

   $entry->save();

}



Grüße,

Hannes

Hi Haensel,

dein Einwand mit der Transaction ist berechtigt. Welches Model nehme ich denn dazu? Also ich muss ja über das Model auf die DB-Connection zugreifen für die Transaction. Oder ist das in dem Fall egal, welches ich nehmen würde. Macht sicherlich Sinn, wenn man das primäre Objekt nimmt (das, das auf jedenfall angelegt werden muss).

oder?

Es macht keinen Unterschied über welches model du die connection erhältst (ich nehme nicht an dass du 2 Datenbanken parallel fährst). Alternativ kannst du auch Yii::app()->db verwenden, dann ist es offensichtlicher.

Komisch, bekomme keine TEST-Ausgabe… es scheint, als würde hier nicht in das IF-gelaufen werden.




	public function actionUpdate($id = null)

	{

		$model = $id ? Activity::model()->findByPk($id) : new Activity();


		$entry = new AEntry;

		

		if (Yii::app()->request->getPost('Activity')) {

			$model->attributes = Yii::app()->request->getPost('Activity');

			$entry->attributes = Yii::app()->request->getPost('AEntry');


			if($model->validate() && $entry->validate())

			{

			   print('Test');

			}

		} 

		else {

			$this->render('update',array(

				'model'=>$model,

				'entry'=>$entry

			));

		}

	}



Auch meine DB-Eingabe (anstelle der Print-Ausgabe) hat dort nicht funktioniert.

Fehler gefunden: Ich durfte im Entry die ID nicht required machen. Macht ja auch Sinn. :slight_smile:

Mal wieder ich :slight_smile: Hallo!

Ich habe folgendes Problem. Ich habe eine m:n-Verbindung (Many_Many). Man könnte sagen: Mieter - Auto. In "Mieter" ist eine Relation zu Auto gesetzt und umgekehrt auch. siehe hier:


'mieter' => array(self::MANY_MANY, 'Mieter', 'auto_has_mieter(Auto_id, Mieter_id)'),

Beim speichern wird der folgende Code ausgeführt:




$model=new Auto;

// Uncomment the following line if AJAX validation is needed

// $this->performAjaxValidation($model);


if(isset($_POST['Auto']))

{

	$model->attributes=$_POST['Auto'];

	if($model->save())

		$this->redirect(array('view','id'=>$model->id));

	}

Es wird aber nichts in die "Zwischentabelle" eingetragen. Ist das normal? Das oben war bisher der Code, den mir gii für CRUD erzeugt hat.

Danke und Gruß

EDIT: Muss ich hier ein eigenes AR-Object von der Zwischentabelle erzeugen und dieses dann manuell abspeichern?

Yii erzeugt keine crosstable (also auto_has_mieter => cooler tabellenname btw :) ) Einträge. Die musst du selbst vornehmen. Eine eigene ActiveRecord Klasse wäre overkill. Aber du kannst diese Extension nutzen oder selbst per DAO bzw. dem querybuilder die Einträge in der Tabelle vornehmen. Dafür könntest du im model methoden anlegen die das tun zb $car->saveWithMieter() oder so ähnlich

Der Name der Crosstable war doch nur ein Beispiel. :slight_smile:

Super, das mit der Extension hat funktioniert. :slight_smile:

AR-Objekt würde aber dann Sinn machen, wenn in der Crosstable noch mehr zeug steht, das ich ggf. editieren möchte. Z.B. ein Datum oder sowas???

Ja, wenn dus wie ein model verwenden willst und zB per formular ändern können willst. Ist halt eher selten der Fall

Wollte neben den beiden IDs halt noch einen weiteren parameter "manuell" reinschreiben. Nur einen festen Wert.

Stell dir vor, ich möchte zu der Info, dass ein Mieter ein Auto gemietet hat auch noch das Datum eintragen. Nehmen wir einfach diesen Fall. Das ist wohl das einfachste. :slight_smile:

Müsste ich dann in diesem Fall die Relation auf Has_Many umstellen und dann mit der o.g. Extension die weiteren Parameter setzen?

Danke und Gruss

Ich muss zugeben ich hab noch nie solch eine Tabelle über ActiveRecord bearbeitet aber das muss im Prinzip wie bei jeder anderen Tabelle funktionieren (nur vermutlich mit einem "composite pk"). Bezüglich deiner "has_many Frage": Da weiß ich nicht was du meinst: Relationen müsstest du in der Verknüpfungstabelle mit BELONGS_TO definieren, da ja jede Zeile zu jeweils einem Mieter und einem Auto gehört und in deinem Mieter bzw. Auto als HAS_MANY statt MANY_MANY. Wenn du so vorgehst und du Zusatzinfos speichern willst ist die genannte Extension vermutlich sogar nicht mehr allzu gut geeignet weil diese ja nur von simplen Verknüpfungen ausgeht. Mach doch sowas wie:




$verknuepfung=new Verknuepfung; //das ist das model für die Vernüpfungstabelle;

$verknuepfung->auto_id=$auto->id; //setze die FKs

$verknuepfung->mieter_id=$mieter->id;

$verknuepfung->attributes=$_POST['Verknuepfung']; //hier könnte eben ein Formular die Zusatzinfos für die Verknüpfung beinhalten, zB irgendeinen Zeitpunkt ab dem das Ding gemietet wird.

if($verknuepfung->save())

    echo 'Sollte jetzt ziemlich verknüpft sein';



Ok, also du bist der Meinung, dass ich in diesem Fall nicht um ein weiteres AR-Model herum komme?

Ist halt doof, aber irgendwie ja auch verständlich. Danke!

Achso, sorry, das hab ich dann falsch verstanden. Natürlich kommst du um AR herum. Das kommst du IMMER, bei allen Tabellen ;) Ich dachte du willst unbedingt ein AR model aus der Tabelle machen. Verwend schlichtweg DAO bzw. den QueryBuilder http://www.yiiframework.com/doc/guide/1.1/en/database.query-builder#preparing-query-builder und schreib halt direkt in die Tabelle. Vor allem wenn der User nicht selbst irgendwelche Daten direkt über ein Formular eingeben soll ist das nämlich einfacher, da du ja keine Validierung benötigst. Deshalb meinte ich wie oben erwähnt, dass AR Modelle in solchen Fällen selten verwendet werden