Reputation: 1933
Here's my beforeSave function. checkExisting() checks whether some of the fields in $this->data are unique, and returns false if there is no existing record, or the ID of the existing record, if it exists. This function is working fine.
public function beforeSave(){
if ($this->checkExisting() !== false){
$this->id = $this->checkExisting();
}
return true;
}
What I think my code should do is this: if there is an existing record, set the Model->id to the ID of that existing record, and so force CakePHP to update instead of insert.
What this code actually does is insert a new record, regardless.
If I change $this->id = $this->checkExisting(); to $this->data['Model']['id'] = $this->checkExisting();, MySQL gives an error (duplicate value for the primary key), as Cake is still trying to insert, rather than update, data.
At what stage does Cake decide to do an insert, rather than an update? Is beforeSave() too late to affect this decision?
Edit - here's my controller code:
public function add(){
if (!empty($this->data)){
$saved = 0;
foreach($this->data['Attendance'] as $att){
$this->Attendance->create();
if ($this->Attendance->save(array('Attendance'=>$att))){
$saved++;
}
if ($saved > 0){
$this->Session->setFlash('Data saved successfully','success');
}else{
$this->Session->setFlash('No data was saved. Please make sure you have entered some data.','failure');
}
}
}
}
Thinking about it, is it something to do with the fact that I explicitly call Attendance::create()?
Upvotes: 4
Views: 7155
Reputation: 45
If your code or Tyler's code work it must be some kind of miracle. When beforeSave is called Cake already did the query to know if the recordset exists and an Update is needed or an Insert otherwise. There is no way you can change to an Update in beforeSave. One possible solution is to delete the recordset if it exists:
public function beforeSave() {
$existing = $this->checkExisting();
if($existing) {
$this->id = $existing;
$this->delete();
}
return true;
}
Upvotes: 2
Reputation: 2126
No, beforeSave is not too late to change this. Model->save() does the following in order:
Your code above should work assuming checkExisting() behaves correctly. I would take another look at your checkExisting() code.
Also note you're code is inefficient in making two calls to checkExisting(). This would be better:
$existing = $this->checkExisting();
if($existing) {
$this->id = $existing;
}
Edit I'm guessing that you've created checkExisting() because your add() action above ends up saving a partial record set if one of the records is invalid. You should be using saveAll(), which can validate all records before saving any of them.
public function add() {
if(!empty($this->data)) {
if($this->Attendance->saveAll($this->data)) {
$this->Session->setFlash('Data saved successfully','success');
} else {
$this->Session->setFlash('No data was saved. Please make sure you have entered some data.','failure');
}
}
}
Upvotes: 2
Reputation: 11574
Is there something you are doing that allows the user to submit a form without the need of the ID? Typically if the user is editing a record, you should already have the ID and not need to check for it when the form is submitted. Then the function in the controller will submit the record with the ID attached, telling the model it is an UPDATE and not a SAVE.
It sounds like to me you may be taking short cuts in the code somewhere. Will you post your controller function that is doing the save/update. Then we can provide the correct help.
Upvotes: 0