ChatGPT解决这个技术问题 Extra ChatGPT

Laravel Eloquent update just if changes have been made

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();
Why not enable database logging and then check the logs to see what query Eloquent actually executes when you do a save: you might be pleasantly surprised
Note that Laravel models hold a 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

l
lukasgeiter

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
}

That's great. Thank you. I wonder now how can I access that dirty flag to know if an attempt of update was made without making any change? I mean: the return for that action?
To those reading this, be sure to check out this answer before using isDirty().
There is getChanges() method. Check my answer stackoverflow.com/a/54132163/1090395
FYI isDirty() will be true 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.
M
Mladen Janjetovic

You can use $product->getChanges() on Eloquent model even after persisting. Check docs here


A
Ahmad Yousef

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 :)


This is actually the answer i was searching for, I forgot about the name 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.