CakePHP - transition from insertion to update in Model-> beforeSave ()

Here is my beforeSave function. checkExisting () checks if some of the fields in $ this-> data are unique, and returns false if there is no existing record or identifier of an existing record if it exists. This function works fine.

public function beforeSave(){ if ($this->checkExisting() !== false){ $this->id = $this->checkExisting(); } return true; } 

I think my code should do this: if there is an existing entry, set the Model-> ID to this existing entry and thus force update CakePHP instead of pasting.

What this code really 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), because Cake is still trying to insert, not update, the data.

At what stage does Cake decide to insert, not update? Is beforeSave () too late to affect this decision?

Edit - here is 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 this, is it because I explicitly call Attendance :: create ()?

+4
source share
3 answers

No, beforeSave is not too late to change this. Model-> save () does the following:

  • Call Model-> set (), passing in the provided data. This retrieves the id and sets Model-> id
  • Calls callback functions (including beforeSave ())
  • Decides whether to update or insert based on the set Model-> parameter

Your code above should work if checkExisting () behaves correctly. I would like to take a look at your checkExisting () code again.

Also note that the code is inefficient when making two calls to checkExisting (). That would be better:

 $existing = $this->checkExisting(); if($existing) { $this->id = $existing; } 

Edit I assume that you created checkExisting () because your add () action above ends saving the partial record if one of the records is invalid. You should use saveAll (), which can check 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'); } } } 
+2
source

If your code or Tyler code work, it must be some kind of miracle. When beforeSave is called Cake, it has already executed a query to find out if there is a recordset and it needs to be updated, or Insert otherwise. You cannot change Update in beforeSave. One possible solution is to delete the recordset, if one exists:

 public function beforeSave() { $existing = $this->checkExisting(); if($existing) { $this->id = $existing; $this->delete(); } return true; } 
+2
source

Is there something you are doing that allows the user to submit the form without an identifier? Usually, if the user is editing an entry, you should already have an identifier and no need to verify it when submitting the form. Then the function in the controller will send the record with the identifier attached, informing the model that this is an UPDATE, not a SAVE.

It looks like you might be shortening the code a bit. You will place your controller function, which performs the save / update. Then we can provide the right help.

0
source

All Articles