Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

laravel - save vs saveorfail (real difference in nutshell)

It's finally time that I understood this concept, because I still don't get some of the cases.

Question 1) what does save() return? is it always boolean or does it throw exceptions sometimes?

Question 2) I am not using any event model. So I don't think save() will return false at any time. So it will return true or throw the exception? am I right?

Question 3) If I have something like this:

DB::beginTransaction();
try{
  $model1 = new Type();
  $model1->test = 'great';
  $model1->save();

  $model2 = new Type();
  $model2->test2 = 'awesome';
  $model2->save();
  DB::commit();
}catch(Exception $e){
  DB::rollBack();
}

Is it possible that save doesn't happen but it doesn't throw the exception? I don't have any events in these models.

Question 4) if the answer for the question 3 is 'no it's not possible', then why do i need to use saveOrFail()

I'd really appreciate that since I really couldn't find anything that deeply explains what I am asking.

like image 488
Nika Kurashvili Avatar asked Aug 14 '19 12:08

Nika Kurashvili


People also ask

What is the difference between save and create in laravel?

Save can be used to both create a new Record and update a existing record . Whereas create is used to create a new record by providing all required field at one time .

What is Save () in laravel?

save() method is used both for saving new model, and updating existing one. here you are creating new model or find existing one, setting its properties one by one and finally saves in database.

How do I save a model in laravel?

To quietly save a model in Laravel you can make use of the "saveQuietly" method available to each model instance. ->saveQuietly();


1 Answers

Question 1) save() can indeed throw exceptions. For example, if you create a model with a decimal column, e.g. 'cost', and try to save a string value in that column, both save() and saveOrFail() will throw an exception. Demo:

>>> $item->cost = 'asdas';
>>> $item->save();
 Illuminate/Database/QueryException with message 'SQLSTATE[HY000]: General error: 1366 Incorrect decimal value: 'asdas' for column 'cost' at row 1 (SQL: update ...

Question 2) Looking through the source, it looks like save() will only return false when firing either the saving, updating or creating events returns false.

Since you haven't defined any event listeners, theoretically yes, you should only ever receive true or an exception will be thrown.

Question 3) If you're not listening to events then no, it's not possible (at least not probable). The save would only not have happened if there was an exception thrown.

Question 4) Since saveOrFail() just wraps save() in a transaction, its use is to keep the database consistent if any exceptions were raised during the save() function. saveOrFail() ensures that if there were any exceptions raised during save(), the model would not have been saved. save() alone would not be able to guarantee that the model was not modified/saved if an exception was thrown.

Since you're already wrapping your code in a transaction, you don't need to use saveOrFail.

For your use case, the best I can think of is to call save() on all of your models in a single if-expression and to commit the transaction only if the expression is true. That way you can cater for both when save() returns false or when it raises an exception. Like this:

DB::beginTransaction();
try {
  $model1 = new Type();
  $model1->test = 'great';
  
  $model2 = new Type();
  $model2->test2 = 'awesome';
  
  if ($model1->save() && $model2->save()) {
    DB::commit();
  } else {
    DB::rollBack();
  }
} catch(Exception $e){
  DB::rollBack();
}
like image 166
D Malan Avatar answered Sep 28 '22 08:09

D Malan