CakePHP: Creating new HABTM row instead updates other

谁说我不能喝 提交于 2019-12-21 05:42:23

问题


I have two models with a HABTM (Has and belongs to many) relationship: Qsets and Questions.

The following action (in QsetsController.php) should result in a new row in the qsets_questions table, with the new question appearing in the new qset. But instead it updates existing rows, resulting in that question begin taken from a previous qset and added to the new one.

What am I doing wrong?

public function admin_add_question( $qset_id, $question_id) {

    //find the qset...
    $qset = $this->Qset->find('first', array('id'=>$qset_id));

    $this->Qset->QsetsQuestion->create();
    $data = array(
            "Qset"=> array ("id"=>$qset_id),
            "Question"=>array ("id"=>$question_id)
    );
    Controller::loadModel('Question');
    $r= $this->Question->save($data);

    $this->Session->setFlash('Question id['.$question_id.'] added.');

    $this->redirect( $this->referer() );
}

In case it wasn't clear from my description, here happens:

Before adding a question...

**Qset 1**
Question 1
Question 2

**Qset 2**
Question 3
Question 4

What should happen when adding Question 2 to Qset 2

**Qset 1**
Question 1
Question 2

**Qset 2**
Question 3
Question 4
Question 2

What happens instead...

**Qset 1**
Question 1
          <----removed
**Qset 2**
Question 3
Question 4
Question 2

update: Here's a dump of my qsets_questions table:

CREATE TABLE `qsets_questions` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `question_id` int(11) NOT NULL,
  `qset_id` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=64 ;

Solution:

Here's the working version, thanks to @nuns

public function admin_add_question( $qset_id, $question_id) {

    $this->Qset->QsetsQuestion->create();
    $data = array(
            "qset_id"=>$qset_id,
            "question_id"=>$question_id
    );
    Controller::loadModel('Question');
    $this->Question->QsetsQuestion->save($data);
    $this->Session->setFlash('Question id['.$question_id.'] added.');       
    $this->redirect( $this->referer() );
}

回答1:


Ok, here is what I think is happening:

Your not using the super useful HABTM relation magic. Instead of treating this table as a mere relation table, cake goes to the defined model an sees the relations you have defined and primaryKeys and displayFields, etc.

That's ok when you have a complicated HABTM table. But if that's the case, your data array is all messed up, because your not adding a Question and Qset separately. What I mean is, your not doing

$data = array('Question'=>array('title'=>'new_question'),
              'Qset'=>array('name'=>'lets say qset'));
$this->Question->saveAll($data);

Doing that, you let cake resolve the HABTM association for you, and that data structure would be ok. But you have your own QsetsQuestion model in you model folder. So the data you save should be like with any other table, like so

$data = array('qset_id'=> $qset_id,
              'question_id'=> $question_id);
$this->Question->QsetsQuestion->save($data);

And that creates a new id in qsets_questions table, with the new relation, just like you want.

Be careful, though, since your using your own model for this, if you don't set you validations correctly, you might have the same pair of foreign keys a lot of times, because by default cake just check that the id must be unique.

[EDIT] After a bit of clarification, the solution above does solve the "problem", but isn't actually the reason for this behavior.

Cakephp has a feature

By default when saving a HasAndBelongsToMany relationship, Cake will delete all rows on the join table before saving new ones. For example if you have a Club that has 10 Children associated. You then update the Club with 2 children. The Club will only have 2 Children, not 12.

So when you want to add a new row, cake deletes all previous associations and add the new ones. A way to solve this is to find all the Qsets that belong to a question and add them to the $data array (with the addition of the new question association you want to add). This link helped me to understand HABTM associations (look for "Challenge IV").

I know the solution I gave before helped you with the "problem", but it was made under the impression you had a QsetsQuestion model file somewhere. Since you don't, the solution would be to get all Questions associated and add them as a new array. Or actually create a QsetsQuestion model, and make the associations like this:

Qset hasMany QsetsQuestion
QsetsQuestion belongsTo Qset, Question
Question hasMany Qsets.

Or change the behavior of cake... None of them seems pretty, I know.

So, summary for solutions:

  • Every time you want to save a new Qset-Question association, retrieve the previously stored associations, put it in the array to be saved, and save them

    //find previously associated Qsets, lets say it's 1,2,3 and 4
    $data = array('Question'=>array('id'=>1),
              'Qsets'=>array('Qsets'=>array(1,2,3,4, $new_qset));
    $this->Question-save($data);
    

Note there's no QsetsQuestion, since it doesn't exists. This should be the first option since the HABTM model is not complex

OR

  • Create QsetsQuestion in your model folder and change the associations as indicated above. The save part on the controller would be

    $data = array('qset_id'=>1, 'question_id'=>1)
    $this->Question->QsetsQuestion->save($data);    //also works with $this->Qset->QsetsQuestion
    

It is much more simple (maybe), but you have to create a new file, and remember to check that there's no previous similar association (check if 2-2 tuple exists before inserting it). Simple validation rules should work.

OR

  • Change cakephp behavior for this... I don't like this one.


来源:https://stackoverflow.com/questions/16220313/cakephp-creating-new-habtm-row-instead-updates-other

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!