Subhasish Saha
Subhasish Saha

Reputation: 13

Editing associated models data in cakephp

I'm using CakePHP 2.3.6. I have some Models in my project, which are associated and I defined the association explicitly. Now, I have an Edit form, where I retrieve all the models data, and trying to edit those data in the corresponding models. But, edition is not happening, instead, new rows are created in the associated tables.

Here is my associations among the models :

in the model User.php :

public $hasMany=array('Education'=>array(
                            'className'=>'Education
                            'foreignKey'=>'user_id'
                      ),
                      'Experience'=>array(
                            'className'=>'Experience',
                            'foreignKey'=>'user_id'
                      ),
                      'Employment'=>array(
                            'className'=>'Employment',
                            'foreignKey'=>'user_id'
                      ),
                      'ProfessionalQualification'=>array(
                            'className'=>'ProfessionalQualification',
                            'foreignKey'=>'user_id'
                      )
)

in the model Education.php :

public $belongsTo=array('User'=>array(
                            'className'=>'User',
                            'foreignKey'=>'user_id'
                        )
)

in the model Experience.php

public $belongsTo=array('User'=>array(
                            'className'=>'User',
                            'foreignKey'=>'user_id'
                        )
)

in the model Employment.php :

public $belongsTo=array('User'=>array(
                            'className'=>'User',
                            'foreignKey'=>'user_id'
                        )
)

in the model ProfessionalQualification.php :

public $belongsTo=array('User'=>array(
                            'className'=>'User',
                            'foreignKey'=>'user_id'
                        )
)

Now, in the Edit form (View/Users/edit.ctp) :

echo $this->Form->create('User');
echo $this->Form->input('User.name');
echo $this->Form->input('User.username');
echo $this->Form->input('User.password');
echo $this->Form->input('User.address');
echo $this->Form->input('User.phone');
echo $this->Form->input('Education.0.degree');
echo $this->Form->input('Education.0.passing_year');
echo $this->Form->input('Experience.0.title');
echo $this->Form->input('Experience.0.description');
echo $this->Form->input('Employment.0.company');
echo $this->Form->input('Employment.0.description');
echo $this->Form->input('ProfessionalQualification.0.certificate');
echo $this->Form->input('ProfessionalQualification.0.description');
echo $this->Form->submit('Save');
echo $this->Form->end();

in the UsersController.php controller :

public function edit(){
  $this->set('title_for_layout','Edit CV');
  if(!AuthComponent::user('id'))
     throw new NotFoundException(__('Invalid User'));
  $user=$this->User->findById(AuthComponent::user('id'));
  if(!$user)
     throw new NotFoundException(__('Invalid User'));
  if($this->request->is('post') || $this->request->is('put')){
     if(!$this->User->saveAll($this->request->data)){
        $this->Session->setFlash('Sorry, your info could not be saved. Please, try again.');
        $this->redirect(array('action'=>'edit'));
     }
  }
  if(!$this->request->data)
     $this->request->data=$user;
}

Here, I am trying saveAll() function on User model. I Also tried using save() & saveAssociated() functions, but same result. It doesn't change the corresponding rows in the tables, instead, it creates a new row in all tables, accept the users table, this table successfully gets the new values and updates the values.

What should I do ? Please help me.

Thanks

Upvotes: 0

Views: 2662

Answers (1)

Holt
Holt

Reputation: 37606

Here is a way to make it works (in theory) but I'm not sure it's the best and, it's not "secure": Adding the id for related field in your form, with hidden field, like so:

echo $this->Form->create('User');
echo $this->Form->hidden('User.id');
echo $this->Form->input('User.name');
/* ... */
echo $this->Form->hidden('Education.0.id');
echo $this->Form->input('Education.0.degree');
/* ... */
echo $this->Form->hidden('Employment.0.id');
echo $this->Form->input('Employment.0.company');
/* ... */
echo $this->Form->submit('Save');
echo $this->Form->end();

You should check in your controller that the id of your associated models match the id of your main model, if not people will be able to edit associated model not linked with their user model.

Edit: This is an edit for further explanation about the discussion in comment.

When you have hasMany relationship, like so:

public $hasMany = array('Experience') ; // In User class

You have to specify ID when saving the relation, if not the Cake engine cannot infer that you want to update a model instead of saving one.

$data = array(
    'User' => array(
        'id' => 33,
        'name' => 'Holt'
    ),
    'Experience' => array(
        array(
            /* 'id' => 45, */
            'name' => 'PHP'
        )
    )
) ;
$this->User->saveAssociated($data) ;

Here, you know that the User you're refering to is Holt with the id 33, and so you know that the experiences in the following array refers to this user. But, if you don't specify the id field in the Experience array, how the engine would know which experience you're refering to?

If the relation was a belongsTo, it's easy to infer that's the Experience related to user Holt (there is only one Experience per user according to relation belongsTo or hasOne), and by the way you wouldn't have a nested array.

There are different ways to tell the engine you want to update a model, the 2 I use are:

  • Setting the id value in the data array (like above)
  • Setting the $this->Model->id value in your controller: This value is implicitely set when you do a $this->Model->read or a $this->Model->find (like you do)

What I'm sure, is that the first option works for associated model (like in the above data array if you uncomment the id), I'm not sure that the second works for associated model, like doing $this->User->Experience->id = ..., you can try it, I cannot check it right now.

Upvotes: 1

Related Questions