Collecting Tabular Input - Mulitple Instances Of Multiple Models

I need to insert data for multiple instances of two models.

Model 1 = ServTransact

Model 2 = ClientSession

For the purposes of this application, these two models have a 1 to 1 relationship joined by the common field SessionNum (primary Key in ServTransact).

I have made partial progress on this, as I am able to save multiple instances of 1 model. However, I need to figure out how to save multiple instances of 2 models. The form consists of tabular html, and I need to collect values from each model in the same row.

Example:


<table>

<tr><th>Service Date</th><th>ClientId</th></tr>

<tr><td>ServTransact.ServDate</td><td>ClientSession.ClientId</td><tr>

<tr><td>ServTransact.ServDate</td><td>ClientSession.ClientId</td><tr>

<tr><td>ServTransact.ServDate</td><td>ClientSession.ClientId</td><tr>

</table>

I have read the yii guide Collecting Tabular Input. This recommendation (stackoverflow.com/questions/13103607/yii-multiple-records-in-one-form-submission) for modifying the aforementioned code for inserting records was also a good starting point. Thanks to this, I have added the following action to my controller:


	public function actionBatchCreate() {

	    $models=array();


//note: eventually $models will be populated via a method that takes more complicated

//criteria into consideration, but that is a separate issue

	    $models[]= new ServTransact;

	    $models[]= new ServTransact;

	    $models[]= new ServTransact;		

					

	    if (isset($_POST['ServTransact'] //add ClientSession)) {

	        $valid=true;

	        foreach ($_POST['ServTransact'] as $j=>$model) {

	            if (isset($_POST['ServTransact'][$j])) {

	                //$models[$j]=new ServTransact; // if you had static model only

	                $models[$j]->attributes=$model;

	                $valid=$models[$j]->validate() && $valid;

	            }

	        }

	        if ($valid) {

	            $i=0;

	            while (isset($models[$i])) {

	                $models[$i]->save(false);// models have already been validated

                        //$models[$i]->SessionNum the foreign key for ClientSession

                        //now save the ClientSession model

		         $i++;           

	            }

	            // anything else that you want to do, for example a redirect to admin page

	            $this->redirect(array('servTransact/admin'));

	        }

	    }

		

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

	    'models'=>$models		

		));

	}

and the form, _form_batch_create.php


<?php

/* @var $this ServTransactController */

/* @var $models ServTransact */

/* @var $form CActiveForm */

?>


<div class="form">

		

<?php echo CHtml::beginForm(); ?>


<?php echo CHtml::errorSummary($models); ?>


<table>

<tr><th>ServDate</th><th>ClientActivity</th><th>SessionLength</th><th>LocOfServ</th></tr>

	<?php foreach($models as $i=>$item):?>

	<tr>

	<td><?php echo CHtml::activeTextField($item,"[$i]ServDate"); ?></td>

<!--would like ClientSession.ClientId to be here-->

	<td><?php echo CHtml::activeTextField($item,"[$i]ClientActivity"); ?></td>

	<td><?php echo CHtml::activeTextField($item,"[$i]SessionLength"); ?></td>

	<td><?php echo CHtml::activeTextField($item,"[$i]LocOfServ"); ?></td>

	</tr>

	<?php endforeach; ?>

</table>

 

<?php echo CHtml::submitButton('Save'); ?>

<?php echo CHtml::endForm(); ?>


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

This is functioning as expected, it allows me to save as many instances of the ServTransact model as I specify in the controller, with the validation error summary for each instance of the model combined together. I can see that all I have to do is pass in the ClientSession models just as I did the ServTransact, but I am having difficulty passing in multiple instances of both models and loading them into the form.

I have solved my problem, but I would like to know if this is considered a best practice. Notice I have to reformat my array of models for the validation error output.

It was partly just an exercise in using arrays. I also re-read the definitive guide to Yii which reinforced the basic principles I was dealing with.

the controller…


	public function actionBatchCreate() {

	    $models=array();


		$models[] = array('model1'=>new ServTransact,'model2'=>new ClientSession);

		$models[] = array('model1'=>new ServTransact,'model2'=>new ClientSession);				

	

	    if (isset($_POST['ServTransact'])) {

	        $valid=true;

	        foreach ($_POST['ServTransact'] as $j=>$model) {

	            if (isset($_POST['ServTransact'][$j])) {

	                //$models[$j]=new ServTransact; // if you had static model only

	                $models[$j]['model1']->attributes=$model;		

	                $valid=$models[$j]['model1']->validate() && $valid;				

	            }

	        }

	        foreach ($_POST['ClientSession'] as $j=>$model) {

	            if (isset($_POST['ClientSession'][$j])) {

	                $models[$j]['model2']->attributes=$model;				

	                $valid=$models[$j]['model2']->validate() && $valid;					

	            }

	        }			

			

	        if ($valid) {

	            $i=0;

				

	            while (isset($models[$i])) {

	                $models[$i]->save(false);// models have already been validated

   	       			print_r($models[$i]->attributes); 

	            	error_log('THIS IS YOUR FK: '.$models[$i]->SessionNum);					

					$i++;           

	            }


	            // anything else that you want to do, for example a redirect to admin page

	            $this->redirect(array('servTransact/admin'));

	        }

	    }

		

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

	    'models'=>$models		

		));

	}

the view…


<div class="form">

	

<?php echo CHtml::beginForm(); ?>

<?php 

/*reformat array of models for errorSummary*/

$array_of_models=array();

foreach($models as $q=>$mgroup) {

	$array_of_models[]=$models[$q]['model1'];

	$array_of_models[]=$models[$q]['model2'];	

}

?>


<?php echo CHtml::errorSummary($array_of_models); ?>


<table>

<tr><th>Client</th><th>ServDate</th><th>ClientActivity</th><th>SessionLength</th><th>LocOfServ</th></tr>

	<?php foreach($models as $i=>$mgroup):?>

	<tr>

	<td><?php echo CHtml::activeTextField($mgroup['model2'],"[$i]ClientId"); ?></td>	

	<td><?php echo CHtml::activeTextField($mgroup['model1'],"[$i]ServDate"); ?></td>

	<td><?php echo CHtml::activeTextField($mgroup['model1'],"[$i]ClientActivity"); ?></td>

	<td><?php echo CHtml::activeTextField($mgroup['model1'],"[$i]SessionLength"); ?></td>

	<td><?php echo CHtml::activeTextField($mgroup['model1'],"[$i]LocOfServ"); ?></td>

    <td></td>	

	</tr>

	<?php endforeach; ?>

</table>

 

<?php echo CHtml::submitButton('Save'); ?>

<?php echo CHtml::endForm(); ?>


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

thank you so much!

@MaxPowers your code seems to be working fine. But still i think that we can clean that code a bit more.

i am going to work on it :)