actionUpdate for a form containing the content of 2 models

Hey guys,

I’m trying to get the actionUpdate() to work for a form, which contains the content of 2 different tables / models.

I played around with this problem for a couple of hours now, but i just cant figure out how i’ll make it work.

My code looks as follows:

view update.php (of the main table (entry)):


....<?php echo $this->renderPartial('_form', array('model'=>$model, 'translation' => $translation)); ?>

actionUpdate (entry):


public function actionUpdate($id)

    {

        $model = $this->loadModel($id);


        // Uncomment the following line if AJAX validation is needed

        $this->performAjaxValidation($model);


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

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

            if ($model->save())

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

        }


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

            'model' => $model,

        ));

    }

loadModel (entry):


public function loadModel()

    {

        if ($this->_model === null) {

            if (isset($_GET['id'])) {

                if (Yii::app()->user->isGuest)

                    $condition = 'status=' . Entry::STATUS_PUBLISHED

                            . ' OR status=' . Entry::STATUS_ARCHIVED;

                else

                    $condition='';

                $this->_model = Entry::model()->findByPk($_GET['id'], $condition);

            }

            if ($this->_model === null)

                throw new CHttpException(404, 'The requested page does not exist.');

        }

        return $this->_model;

    }

The relation between entry and translation is: entry has many translations.

My thought was to use the loadModel() function in the EntryController to retrieve both tables. but i just doesn’t want to work …

Would be great if one of you guys could give me some advice here.

Tanks in advance,

Mayjestic

This minimal change should at least lazy load the related record into $translation in the view




echo $this->renderPartial(

  '_form', 

  array(

    'model'=>$model, 

    'translation' =>$model->translation

  )

);



For eager loading you just need to add ->with(‘translation’)-> to the query.

/Tommy

Thanks very much for your reply.

Thanks to you i at least could show the "old" dataset when calling for an update.

The only problem i got now is, that i can create any "entry" anymore. I always get the error

"Fatal error: Call to a member function isAttributeRequired() on a non-object in C:\xampp\htdocs\Yii\framework\web\helpers\CHtml.php on line 1166"

There must be something wrong with the _form.php file, but Im still too noob in yii to figure out what’s wrong.

My view file looks as follows (using the tinymce widget for 1 field):


<div class="form">


    <?php

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

                'id' => 'entry-form',

                'enableAjaxValidation' => true,

            ));

    ?>


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


    <?php /* echo CHtml::errorSummary(array($model, $translation)); */ ?>


    <div class="row">

        <?php echo $form->labelEx($model->translations[0], 'title'); ?>

        <?php echo $form->textArea($model->translations[0], 'title', array('rows' => 1, 'cols' => 50)); ?>

        <?php echo $form->error($model->translations[0], 'title'); ?>

    </div>


    <div class="row">

        <?php echo $form->labelEx($model->translations[0], 'content'); ?>

        <?php

        $this->widget('application.extensions.tinymce.ETinyMce',

                array('name' => 'Translation[content]',

                    'value' => 'Translation[content]',

                    'options' => array(

                        'theme' => 'advanced',

                        'skin' => 'o2k7',

                    /* fruther options... */

                    ),

                    'htmlOptions' => array(

                        'rows' => 30,

                        'cols' => 30,

                        'style' => 'width:600px;height:300px;',

                    ),

                    'value' => $model->translations[0]->content,

        )); ?>

        <?php echo $form->error($model->translations[0], 'content'); ?>

    </div>


    <div class="row">

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

        <?php echo $form->textArea($model, 'tags', array('rows' => 1, 'cols' => 50)); ?>

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

    </div>


    <div class="row">

        <?php echo $form->labelEx($model->translations[0], 'language_code'); ?>

        <?php echo $form->dropDownList($model->translations[0], 'language_code', Lookup::items('language')); ?>

        <?php echo $form->error($model->translations[0], 'language_code'); ?>

    </div>


    <div class="row">

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

        <?php echo $form->dropDownList($model, 'type', Lookup::items('type')); ?>

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

    </div>


    <div class="row">

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

        <?php echo $form->dropDownList($model, 'status', Lookup::items('PostStatus')); ?>

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

    </div>


    <div class="row buttons">

        <?php echo CHtml::submitButton($model->isNewRecord ? 'Create' : 'Save'); ?>

    </div>




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


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

The update.php:


<?php

$this->breadcrumbs=array(

	'Entries'=>array('index'),

	$model->entry_id=>array('view','id'=>$model->entry_id),

	'Update',

);


$this->menu=array(

	array('label'=>'List Entry', 'url'=>array('index')),

	array('label'=>'Create Entry', 'url'=>array('create')),

	array('label'=>'View Entry', 'url'=>array('view', 'id'=>$model->entry_id)),

	array('label'=>'Manage Entry', 'url'=>array('admin')),

);

?>


<h1>Update Entry <?php echo $model->entry_id; ?></h1>


<?php echo $this->renderPartial('_form', array('model'=>$model, 'translation' => $model->translations[0])); ?>

And the create.php:


<?php

$this->breadcrumbs=array(

	'Entries'=>array('index'),

	'Create',

);


$this->menu=array(

	array('label'=>'List Entry', 'url'=>array('index')),

	array('label'=>'Manage Entry', 'url'=>array('admin')),

);

?>


<h1>Create Entry</h1>


<?php echo $this->renderPartial('_form', array('model'=>$model, 'translation' => $model->translations[0])); ?>



Ahh one more thing i got to say: the translations[0] is just for the moment to make it run :wink: … the loop over more than 1 translation I will make later on, so dont wonder about that ;-).


EDIT: any advice for "better" code is always welcome! - still learning to handle the yii framework ;-).

EDIT2: the problem should be something with these parts of code … "[color="#FF0000"]$model->translations[0][/color]" … thats what i could figure out so far …

You have a design problem with the combined use in create/update actions and the multiple translations. In the view you want to iterate over multiple translations which would be fine for presentation and perhaps if there’s an existing translation to update. If there’s no translation object present you will get the error message.

Perhaps you may want to split the view into two forms and use tabular input for translations.

With just one translation it should work to pass $model and $translation in separate variables and add new Model/new Translation in the create action (like in this wiki).

(BTW, in the view you posted you don’t at all use the $translation variable passed from the controller.)

/Tommy

Thanks a lot - again - /Tommy,

it’s working now (with 2 different forms for create and update). The tabular input looks also like what I was looking for. I’ll check that out later.

forgot about that point. What do you mean exactly, or could you tell me how to use the $translation variable? … sorry - like i sayed. I’m using Yii for 4 or 5 days now and in PHP I’m not a master yet as well…

The value that corresponds to the translation key in the array you pass as second parameter to render(), will be available in the $translation variable in the view.

/Tommy

Ahh, allright. Now i understand… thanks a lot again!