Is there any way to update a record in Laravel using eloquent models just if a change has been made to that record? I don't want any user requesting the database for no good reason over and over, just hitting the button to save changes. I have a javascript
function that enables and disables the save button according with whether something has changed in the page, but I would like to know if it's possible to make sure to do this kind of feature on the server side too. I know I can accomplish it by myself (meaning: without appealing to an internal functionality of the framework) just by checking if the record has change, but before doing it that way, I would like to know if Laravel eloquent model already takes care of that, so I don't need to re-invent the wheel.
This is the way I use to update a record:
$product = Product::find($data["id"]);
$product->title = $data["title"];
$product->description = $data["description"];
$product->price = $data["price"];
//etc (string values were previously sanitized for xss attacks)
$product->save();
dirty
flag that is used to determine if an update on the database is actually required, and this flag is set by comparing original find
column values with the values at the point where you execute the save
You're already doing it!
save()
will check if something in the model has changed. If it hasn't it won't run a db query.
Here's the relevant part of code in Illuminate\Database\Eloquent\Model@performUpdate
:
protected function performUpdate(Builder $query, array $options = [])
{
$dirty = $this->getDirty();
if (count($dirty) > 0)
{
// runs update query
}
return true;
}
The getDirty()
method simply compares the current attributes with a copy saved in original
when the model is created. This is done in the syncOriginal()
method:
public function __construct(array $attributes = array())
{
$this->bootIfNotBooted();
$this->syncOriginal();
$this->fill($attributes);
}
public function syncOriginal()
{
$this->original = $this->attributes;
return $this;
}
If you want to check if the model is dirty just call isDirty()
:
if($product->isDirty()){
// changes have been made
}
Or if you want to check a certain attribute:
if($product->isDirty('price')){
// price has changed
}
I like to add this method, if you are using an edit form, you can use this code to save the changes in your update(Request $request, $id)
function:
$post = Post::find($id);
$post->fill($request->input())->save();
keep in mind that you have to name your inputs with the same column name. The fill()
function will do all the work for you :)
fill
, and how to mass pass request to it. Thanks! I didnt need to pass the ID though, since im updating, so its already there $request->id
.
Success story sharing
isDirty()
.getChanges()
method. Check my answer stackoverflow.com/a/54132163/1090395isDirty()
will betrue
if you do not cast your attributes right. I had a float that was exactly the same as in the database, however because I was setting the float with a string (example "10.50" instead of 10.50) it would detect it as a change and perform an update.