What is the difference between save() and update() method in Laravel.
I have used save() method in case of update query but in few cases it acts as update and in few case it act as insert query function. Please let me know what exactly the difference between them.
These methods both allow you to save data to a database.
The save() method performs an INSERT when you create a new model which is currently is not present in your database table:
$flight = new Flight;
$flight->name = $request->name;
$flight->save(); // it will INSERT a new record
Also it can act like an UPDATE, when your model already exists in the database. So you can get the model, modify some properties and then save() it, actually performing db's UDPATE:
$flight = App\Flight::find(1);
$flight->name = 'New Flight Name';
$flight->save(); //this will UPDATE the record with id=1
Theupdate() method allows you to update your models in more convenient way:
App\Flight::where('active', 1)
->where('destination', 'San Diego')
->update(['delayed' => 1]); // this will also update the record
So you don't even need to assign the retrieved model to any variable. Updated properties are passed as arguments.
Examples and more info in the Laravel's docs.
There is only one thing left unsaid in what #ginopane told about the difference and it's that if you use update method on a query builder result then laravel will ignore $fillable or $guard array of your model. This is especially important if you want to use Input::all() as an argument to update:
Post::where('id', $id)->update(Input::all());
So in this case if you use App\Flight::where('active', 1)->update(Input::all()); everything in your database will be updated even if you put it in $fillable. So make sure to use save and update methods on Eloquent instance and not Query builder one. The following code will be fine even if the user submit fields that you don't want to insert or update in your databse table:
// User model
protected $fillable = ['email', 'name'];
// controller
public function update($id)
{
$user = User::findOrFail($id);
// validate the input here, use Request to do the job or whatever you like
$user->update(Input::all());
return view('some_view')->with('notice', 'user updated');
}
Now, no matter what with the FORM being passed here, only name and email will be updated.
Hope this complete #ginopane answer
save() : you can look to it as the equivalent of the INSERT in sql, it will create a new model (and insert it in the database)
To create a new record in the database, create a new model instance, set attributes on the model, then call the save method
update() : you can look to it as the equivalent of the UPDATE in sql, it will create a new model (and insert it in the database)
The save method may also be used to update models that already exist in the database. To update a model, you should retrieve it, set any attributes you wish to update, and then call the save method. Again, the updated_at timestamp will automatically be updated, so there is no need to manually set its value
code
$flight = App\Flight::find(1);
if (empty($flight)) {// you can do this condition to check if is empty
$flight= new Flight;//then create new object
}
$flight->name = 'New Flight Name';
$flight->save(); //this will UPDATE the record with id=1
for more detail doc
Related
I understand Laravel is checking the object reference id to check if the object existed, so the save() method will run the edit method to edit it. and if it's a new object, it will run the create() method.
but I can't find the codes behind it, in the Eloquent package.
I want the exact address of the file that includes these codes
from the blow codes I infer the above conclusion:
I wrote this code in Laravel:
$setting = new Setting;
$setting->name = 'name1';
$setting->save();
$setting->name = 'name2';
$setting->save();
after executing I see just name2 in the database and it seems, after saving name1 Laravel edit that and save name2 in the database.
and after I execute this code:
$setting = new Setting;
$setting->name = 'name1';
$setting->save();
$setting = new Setting;
$setting->name = 'name2';
$setting->save();
and I saw both the records saved correctly, so I have name1 and name2.
You can find the code for Eloquent's save() method in vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php on line 833 in Laravel 8.12.
The behaviour that you're observing is a characteristic of the Active Record pattern, which Laravel is based on. Each time you use new to create an Eloquent model, it's creating a object that will represent a row in your database. Within Eloquent's save() method, it will check to see if a record already exists, and if it does it will update it (code below).
if ($this->exists) {
$saved = $this->isDirty() ?
$this->performUpdate($query) : true;
}
Your code is working as expected.
I have a form where the user can edit, create or delete shipping methods.
The user sends the form and the data is updated.
I want to return the user's shipping methods after they are edited.
But I seem to get the old data back, instead of the updated data.
$user = \App\User::where('user_id', $user->id)->first();
$user->shipping_methods->each(function($method) {
$method->delete();
});
$methods = [];
foreach ($request->input('methods') as $method) {
$methods[] = new \App\ShippingMethod($method);
}
$user->shipping_methods()->saveMany($methods);
return response()->json($user->shipping_methods->toArray());
(at the moment the code just deletes the old shipping methods and replaces them with the new ones). I am using eloquent relations to get the shipping methods.
So when I do:
return response()->json($user->shipping_methods->toArray());
how come I don't get the new results, instead I get the results from before the update? Is it using the results from the first $user->shipping_methods at line 3? Should I "refresh" the query somehow?
You have to reload the relationship:
return response()->json($user->load('shipping_methods')->shipping_methods->toArray());
You can also simplify the whole line:
return $user->load('shipping_methods')->shipping_methods;
The saveMany method of \Illuminate\Database\Eloquent\Relations\HasMany return instace of \Illuminate\Database\Eloquent\Collection and you must manually set relations
$shipping_methods = $user->shipping_methods()->saveMany($methods);
$user->setRelation('shipping_methods', $shipping_methods);
return response()->json($user->shipping_methods->toArray());
I have a flight class and this flight has a custom view field like so:
This represents a belongs to many relationship which stores website_id / flight_id and pricing as pivot data in a pivot table.
The custom view uses JS to send this data back to the controller in this format:
{"1":{"price_adult":"434","price_child":"545"},"2":{"price_adult":"323","price_child":"324"},"3":{"price_adult":"434","price_child":"43"}}
Trying to send this data with the request doesn't create the relations fields, and because I do not have a flight ID at the point of creating this within the controller I can not loop this JSON to make the relations manually.
Can anyone point out what the best course of action is or if there is support for this? I took a look at the docs but they are woefully short and patchy in terms of being much help.
EDIT:
I should have said I can probably make this work using a custom name attribute on the model for the relation, then add a set mutator to loop this data and update the prices relation but I don't want to go down this route if there is support for this I am missing out of the box in backpack.
EDIT2:
Someone asked about the relation:
$this->belongsToMany(Website::class, 'website_pricing')->withPivot('price_adult', 'price_child');
This is working fine its not a problem with the relation working its how can I get backpack to store the data as a relation when the flight has no ID yet, or how can I pass the data I posted above in such a way that the backpack crud controller can handle it?
You may need to create a flight first, if no flight id is being provided. Can you explain the database relational structure more?
Basically thought I should post what I did because no one could provide an answer to this.
So basically you have to copy the store / update functions from the parent, changing a few lines.
$this->crud->hasAccessOrFail('create');
// fallback to global request instance
if (is_null($request)) {
$request = \Request::instance();
}
// replace empty values with NULL, so that it will work with MySQL strict mode on
foreach ($request->input() as $key => $value) {
if (empty($value) && $value !== '0') {
$request->request->set($key, null);
}
}
// insert item in the db
$item = $this->crud->create($request->except(['save_action', '_token', '_method']));
$this->data['entry'] = $this->crud->entry = $item;
// show a success message
\Alert::success(trans('backpack::crud.insert_success'))->flash();
// save the redirect choice for next time
parent::setSaveAction();
return parent::performSaveAction($item->getKey());
Basically any line which references a function in the parent class using $this->method needs to be changed to parent::
This line is what I used to submit the relations JSON string passed to the controller as relations $item->prices()->sync(json_decode($request->input('prices'), true));
This is done after the line containing $item = $this->crud->create as the item id that just got stored will be available at that point.
How to avoid querying relationship after object creation?
$store = new Store();
$store->name = 'Store 1';
$store->save();
return response()->json($store->products());
Laravel is querying products table. I would like to avoid that since I know there is none. This is just an example.
return response()->json([]); is not an option. In real world I really need to use $store->products().
Use the wasRecentlyCreated property of model to identify if the model was inserted during the current request lifecycle.
$data = $store->wasRecentlyCreated ? [] : $store->products();
I am sending a bunch of data through post method. For now I am using a fully working solution:
$dataClient = new Client;
$dataClient->name = $post['client']['name'];
$dataClient->address = $post['client']['address'];
...
$dataClient->save();
I am wondering if there is a shorter solution? Like posting an array and Laravel could map keys to db fields?
What if you would add something more, like calculated value upon?
Example:
$dataClient = new Client;
Then map array keys to db keys
$dataClient->someField = someCalculatedValue
$dataClient->save();
Thank you in advance.
You have quite a few options when it comes to creating models from a data array. If you want to directly insert it into the database, the easiest way is create()
Client::create($post['client']);
If you want to change some things afterwards or just not save it right away, just pass your data to the constructor.
$client = new Client($post['client']);
$client->someField = 'some value';
$client->save();
And finally, the last option, calling fill() manually. This method is used internally for create() as well as in the constructor.
$client = new Client();
$client->fill($post['client']);
$client->save();
Note: for all methods above you'll need to set up the fillable attributes in your model. This is to protect against malicious user input (request data).
protected $fillable = ['name', 'address', 'etc'];
More information about Mass Assignment
Eloquent has create and update methods which will insert massive data. For example :
inputs = ['name' => 'value','address' => 'value'];
Client::create(inputs)
It will automatically map fields in Eloquent.
Have you tried something like this?
$dataClient = new Client;
$dataClient->fill($client);
$dataClient->save();
Depending on how you set up your Client model and what fields you set as guarded/fillable, the fill method will automatically map the data with their respective fields.