I’ve struggled to understand the nested form as the example in the Documentation talks about using CForm while if you generate the forms using CRUD via Gii it uses CActiveForm which behaves differently than CForm.
Now I’ve managed to create one page with one form for two different data models -hopefully I’ve done it right.
I have a User model with ID, Username, Password and a UserDetail model with Id, User_Id (FK), FirstName, LastName
so what I have done is to work on the UserDetail controller for the action update to also add the User model (username and password)the method’s code looks like this
public function actionUpdate()
{
$userDetailModel=$this->loadModel();
$userModel=new User;
// Uncomment the following line if AJAX validation is needed
$this->performAjaxValidation($userDetailModel);
$this->performAjaxValidation($userModel);
if(isset($_POST['UserDetail']) && isset($_POST['User']))
{
// HERE IS WERE I SAVE BUT WILL TALK ABOUT THIS BIT LATER
}
$this->render('update',array(
'userDetailModel'=>$userDetailModel,
'userModel'=>$userModel,
));
}
Now the userDetail view is composed by two part, the partial _form and the userDetail view itself, i’m including here only the partial as the main view contains nothing substantial.
<div class="form">
<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'user-detail-form',
'enableAjaxValidation'=>false,
)); ?>
<p class="note">Fields with <span class="required">*</span> are required.</p>
<?php echo $form->errorSummary($userDetailModel); ?>
<?php echo $form->errorSummary($userModel); ?>
<div class="row">
<?php echo $form->labelEx($userModel,'username'); ?>
<?php echo $form->textField($userModel,'username',array('size'=>60,'maxlength'=>128)); ?>
<?php echo $form->error($userModel,'username'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($userModel,'password'); ?>
<?php echo $form->passwordField($userModel,'password',array('size'=>60,'maxlength'=>128)); ?>
<?php echo $form->error($userModel,'password'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($userDetailModel,'email'); ?>
<?php echo $form->textField($userDetailModel,'email',array('size'=>60,'maxlength'=>80)); ?>
<?php echo $form->error($userDetailModel,'email'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($userDetailModel,'first_name'); ?>
<?php echo $form->textField($userDetailModel,'first_name',array('size'=>60,'maxlength'=>80)); ?>
<?php echo $form->error($userDetailModel,'first_name'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($userDetailModel,'last_name'); ?>
<?php echo $form->textField($userDetailModel,'last_name',array('size'=>60,'maxlength'=>80)); ?>
<?php echo $form->error($userDetailModel,'last_name'); ?>
</div>
<div class="row buttons">
<?php echo CHtml::submitButton($userDetailModel->isNewRecord ? 'Create' : 'Save'); ?>
</div>
<?php $this->endWidget(); ?>
</div><!-- form -->
Now everything works in terms of loading the correct data, however the directions I’ve followed from the documentation and from some tutorials advocate that my saving/update statement should look like this:
$user = $form['user']->model;
$profile = $form['profile']->model;
if($user->save(false))
{
$profile->userID = $user->id;
$profile->save(false);
$this->redirect(array('site/index'));
}
now transposing the above for my code an putting it in the saving statement (where I’ve put the comment in the code above) I should have something like this (remember I am working with UserDetail and not User)
if($userDetailModel->save(false))
{
$userModel->id = $userDetailModel->user_id;
$userModel->save(false);
$this->redirect(array('site/index'));
}
the code above will result in a data integrity exception error from SQL, because it is attempting to create a new record in the table user with an existing ID… At this point I’ve got lost what I want to do is to update an existing record and not creating a new one.
Digging around I’ve found somebody else using another method where the code above transform in a oneliner
if($userDetailModel->save(false) && $userModel->updateByPk($userDetailModel->user_id,$_POST['User']))
$this->redirect(array('update','id'=>$userDetailModel->id));
I’ve tried it and works perfectly, my question is: Is this the correct approach? Why I have to use updateByPk method and not a more intuitive save() on the object?
I’m quite new to Yii not to OOP or PHP though, have been developing for over a decade. Any comment/suggestion is very welcome.
Thanks.
Cheers.