Search code examples
phpyiiforeachmulti-model-forms

Yii multi model with HAS_MANY Tabular form


I have been trying to find a solution to something that I believe is rather simple? What I would like to do is create a tabular form to collect some records for a survey.

Table: survey_record
id
meter_id
status_id
create_time
create_user

Table: survey_inspection
id
survey_record_id (FK)
bay_id
bay_usage_id

So table survey_inspection HAS_MANY inspections from survey_record. Assuming an inspector is doing a survey for meter_id = 1001, the user identifies the status_id of the meter then, they have to fill in 4 inspection entries, as 1001 has 4 bays. To generate the 4 bays I simply created a for loop. Which works fine.

View: _form.php

...
$meter=Meter::model()->findByPk($model->meter_id);
$bays = count($meter->bays); //retrieves the number of inspections required

<?php echo $form->dropDownListRow($model,'status_id',$model->getStatusId(),array('prompt'=>'Select Status ...')); ?>

...
<?php for ($i = 1; $i <= $bays; $i++): ?>

<?php echo $form->textFieldRow($inspection, "[$i]bay_id", array('readonly'=>true, 'value'=>"$i", 'class'=>'span1')); ?>

<?php echo $form->dropDownListRow($inspection, "[$i]bay_usage_id", $inspection->getUsageId(), array('prompt'=>'Bay Status ...') ); ?>   

<?php endfor; ?>
...

However when I submit the form I am only receiving two (not four) results and I can't seem to display the validated fields correctly. So here's the famous controller file:SurveyRecordController.php

public function actionCreate($survey_id, $meter_id)
{

    $model=new SurveyRecord;
    $inspection = new SurveyInspection;

    $model->survey_id = (int)$survey_id;
    $model->meter_id  = (int)$meter_id;


    if(isset($_POST['SurveyRecord'], $_POST['SurveyInspection']))
    {
        $model->attributes=$_POST['SurveyRecord'];
        $valid= $model->validate();

            $i=1;
            foreach($_POST['SurveyInspection'][$i] as $inspection)
            {
                $inspection = new SurveyInspection;

                $inspection->bay_id     =$_POST['SurveyInspection'][$i]['bay_id'];
                $inspection->bay_usage_id   =$_POST['SurveyInspection'][$i]['bay_usage_id']; 


                $valid= $inspection->validate() && $valid; 

                echo '<br/><br/><br/><pre>';
                print_r($_POST['SurveyInspection'][$i]);
                echo '</pre>';

                if($valid)
                {
                    if($model->save(false))
                    {
                        $inspection->survey_record_id = $model->id;
                        $inspection->save(false); 
                        $this->redirect(array('/meter')); 
                    }
                }
                $i++;

                //$inspection->attributes=$_POST['SurveyInspection'][$i];

            }


    }

    $this->render('create',array(
        'model'=>$model,
        'inspection'=>$inspection,
    ));
}

I have a funny feeling that I may not be doing the foreach loop correctly as when I view the array $_POST['SurveyInspection'][$i] I am only returned with two entries when there should be four.

Some information that may be helpful:

PHP version: 5.4.14
Yii version: 1.1.13
PostgreSQL version: 9.1.9

Thank you kindly :)


Solution

  • I've taken a completely different approach, valuable suggestions are always welcome :) Hope this will be helpful for some of you.

    Controller:

    public function actionCreate($survey_id, $meter_id)
    {
    
        $bays = $this->getBayCount($meter_id);
    
        for ($i=1;$i<=$bays;$i++)
        {   
            $model=new SurveyRecord;
            $model->survey_id = (int)$survey_id;
            $model->meter_id  = (int)$meter_id;
            ${'inspection_'.$i} = new SurveyInspection($i);
    
            if(isset($_POST['SurveyRecord'], $_POST["SurveyInspection"][$i]))
            {
                $model->attributes = $_POST['SurveyRecord'];
                ${'inspection_'.$i}->attributes = $_POST["SurveyInspection"][$i];
    
    
                echo '<br/><br/><br/><pre>';
                print_r(${'inspection_'.$i}->attributes);
                echo '</pre>';
    
            }
    
        }
    
        for ($i=1;$i<=$bays;$i++)
        {
            ${'inspection_'.$i} = new SurveyInspection($i);
            $inspection['inspection_'.$i] = ${'inspection_'.$i};
        }
    
        $this->render('create',array(
        'inspection'=>$inspection,
        'model'=>$model
        )); 
    
    }
    

    View:

    ...
    <div class="control">
    <?php echo $form->dropDownListRow($model,'status_id',$model->getStatusId(),array('prompt'=>'Select Status ...')); ?>
    
    <?php
        $meter=Meter::model()->findByPk($model->meter_id);
        $bays = count($meter->bays);
    ?>
    <?php for ($i=1; $i<=$bays; $i++): ?>
    <table>
    <tr>
        <td><?php echo $form->textFieldRow($inspection["inspection_$i"], "[$i]bay_id", 
            array('readonly'=>true, 'value'=>"$i", 'class'=>'span1')); ?></td>
        <td><?php echo $form->dropDownListRow($inspection["inspection_$i"], "[$i]bay_usage_id", $inspection["inspection_$i"]->getUsageId(),
            array('prompt'=>'Bay Status ...') ); ?></td>    
    </tr>
    </table>
    <?php endfor; ?>    
    
    </div>
    ...
    

    Credit: http://yiiblog.info/blog/index.php/post/108/Rename+ACtiveRecord+$_POST+array's+Name+to+update+multimodels

    Note: There's still some work to be done on the view/controller (doesn't seem to be able to select on $_POST for my dropdowns on second model), will post once I have fixed it.

    Thanks for your help @PeterM and @Ninad for your input.