Обновление Laravel Eloquent, если были внесены изменения

86

Есть ли способ обновить запись в Laravel, используя красноречивые модели, только если в эту запись было внесено изменение? Я не хочу, чтобы какой-либо пользователь снова и снова запрашивал базу данных без уважительной причины, просто нажимая кнопку, чтобы сохранить изменения. У меня есть javascriptфункция, которая включает и отключает кнопку сохранения в зависимости от того, изменилось ли что-то на странице, но я хотел бы знать, можно ли сделать такую ​​функцию и на стороне сервера. Я знаю, что могу сделать это сам (то есть: не обращаясь к внутренней функциональности фреймворка), просто проверив, есть ли изменения в записи, но прежде чем делать это таким образом, я хотел бы знать, заботится ли уже о красноречивой модели Laravel это, поэтому мне не нужно заново изобретать колесо.

Вот как я использую для обновления записи:

$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();
user2755140
источник
3
Почему бы не включить ведение журнала базы данных, а затем проверить журналы, чтобы увидеть, какой запрос Eloquent на самом деле выполняет при сохранении: вы можете быть приятно удивлены
Марк Бейкер
4
Обратите внимание, что модели Laravel содержат dirtyфлаг, который используется для определения, действительно ли требуется обновление базы данных, и этот флаг устанавливается путем сравнения исходных findзначений столбцов со значениями в точке, где вы выполняете сохранение
Марк Бейкер,
@MarkBaker Отличный совет!
user2755140 04

Ответы:

177

Вы уже это делаете!

save()проверит, изменилось ли что-нибудь в модели. Если это не так, он не будет запускать запрос к базе данных.

Вот соответствующая часть кода Illuminate\Database\Eloquent\Model@performUpdate:

protected function performUpdate(Builder $query, array $options = [])
{
    $dirty = $this->getDirty();

    if (count($dirty) > 0)
    {
        // runs update query
    }

    return true;
}

getDirty()Метод просто сравнивает текущие атрибуты с копией , сохраненной в originalмомент создания модели. Это делается в syncOriginal()методе:

public function __construct(array $attributes = array())
{
    $this->bootIfNotBooted();

    $this->syncOriginal();

    $this->fill($attributes);
}

public function syncOriginal()
{
    $this->original = $this->attributes;

    return $this;
}

Если вы хотите проверить, не загрязнена ли модель, просто позвоните isDirty():

if($product->isDirty()){
    // changes have been made
}

Или, если вы хотите проверить определенный атрибут:

if($product->isDirty('price')){
    // price has changed
}
Лукасгейтер
источник
Замечательно. Спасибо. Интересно теперь, как я могу получить доступ к этому грязному флагу, чтобы узнать, была ли предпринята попытка обновления без каких-либо изменений? Я имею в виду: отдача от этого действия?
user2755140 04
1
@DaseinA Вы можете использовать isDirty()для этого. См. Обновленный ответ
lukasgeiter
2
Тем, кто читает это, обязательно ознакомьтесь с этим ответом перед использованием isDirty().
Alex
1
Есть getChanges()метод. Проверьте мой ответ stackoverflow.com/a/54132163/1090395
Младен Джанжетович
FYI isDirty()будет, trueесли вы не укажете свои атрибуты правильно. У меня было число с плавающей запятой, которое было точно таким же, как в базе данных, однако, поскольку я устанавливал число с плавающей запятой со строкой (например, «10,50» вместо 10,50), он обнаруживал бы его как изменение и выполнял обновление.
Maarten de Graaf,
18

Вы можете использовать getChanges()модель Eloquent даже после сохранения.

Младен Янетович
источник
11

Мне нравится добавлять этот метод, если вы используете форму редактирования, вы можете использовать этот код для сохранения изменений в вашей update(Request $request, $id)функции:

$post = Post::find($id);    
$post->fill($request->input())->save();

имейте в виду, что вы должны называть свои поля ввода одним и тем же именем столбца. fill()Функция будет делать всю работу за вас :)

Ахмад Юсеф
источник
3
На самом деле это ответ, который я искал, я забыл об имени fillи о том , как массово передать ему запрос. Благодарность! Мне не нужно было передавать идентификатор, так как я обновляю, так что он уже там $request->id.
blamb