Yii Framework Forum: nested form with CActiveForm and updating record --- SOLVED - Yii Framework Forum

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

nested form with CActiveForm and updating record --- SOLVED Rate Topic: -----

#1 User is offline   pingala 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 15
  • Joined: 14-July 10
  • Location:Dublin, Ireland

Posted 14 July 2010 - 10:29 AM

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.
0

#2 User is offline   Kavi 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 1
  • Joined: 14-July 10

Posted 14 July 2010 - 10:27 PM

Try to use the blog example.

The update action:
public function actionUpdate()
{
$model=$this->loadModel();
if(isset($_POST['Post']))
{
$model->attributes=$_POST['Post'];
if($model->save())
$this->redirect(array('view','id'=>$model->id));
}
$this->render('update',array(
'model'=>$model,
));
}

I guess you code will be a little bit different and you will use both $userDetailModel and $userModel models.
0

#3 User is offline   pingala 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 15
  • Joined: 14-July 10
  • Location:Dublin, Ireland

Posted 15 July 2010 - 05:22 AM

View PostKavi, on 14 July 2010 - 10:27 PM, said:

Try to use the blog example.

The update action:
public function actionUpdate()
{
$model=$this->loadModel();
if(isset($_POST['Post']))
{
$model->attributes=$_POST['Post'];
if($model->save())
$this->redirect(array('view','id'=>$model->id));
}
$this->render('update',array(
'model'=>$model,
));
}

I guess you code will be a little bit different and you will use both $userDetailModel and $userModel models.


I'm afraid your comment doesn't really help, thanks for trying.

Is there anybody else from the Yii core community who may be able to suggest best practices here?

Thanks
0

#4 User is offline   zaccaria 

  • Elite Member
  • PipPipPipPipPip
  • Yii
  • Group: Members
  • Posts: 2,232
  • Joined: 04-October 09
  • Location:Moscow

Posted 16 July 2010 - 04:29 AM

Your mistake is the second line of action update:

        public function actionUpdate()
        {
                $userDetailModel=$this->loadModel();
                $userModel=new User;


I suppose that the model you need already exist in database (or you should not get the data integrity exception error from SQL), so maybe you can do something like that:
        public function actionUpdate()
        {
                $userDetailModel=$this->loadModel();
                $userModel=$userDetailModel->user;


Under the hipotesys that in userDetail there is a relation named "user" that refers to his own user.


For "best practice with multiple form" give a look to this post
0

#5 User is offline   pingala 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 15
  • Joined: 14-July 10
  • Location:Dublin, Ireland

Posted 16 July 2010 - 05:51 AM

View Postzaccaria, on 16 July 2010 - 04:29 AM, said:

Your mistake is the second line of action update:

        public function actionUpdate()
        {
                $userDetailModel=$this->loadModel();
                $userModel=new User;



Hi there, yes I've soon realized yesterday that the problem was in there as I was creating a new object instead of loading up the related recordset linked to the user detail table.

Firstly I've created a method in the user detail controller to load the parent model ... but

Quote

I suppose that the model you need already exist in database (or you should not get the data integrity exception error from SQL), so maybe you can do something like that:
        public function actionUpdate()
        {
                $userDetailModel=$this->loadModel();
                $userModel=$userDetailModel->user;


Under the hipotesys that in userDetail there is a relation named "user" that refers to his own user.


soon I've realized that I've forgot there were relations defined between the data models, and came up
to the same solution you proposed.

It took a little bit of suffering but I've got there, and that's good.

Quote

For "best practice with multiple form" give a look to this post


thanks a lot for the link. This is the kind of things the documentation and tutorial should includes as sometime people get lost in those simple things and give up using an excellent tool like this one is.

Cheers
T.
0

Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users