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();

3
Чому б не увімкнути ведення журналу баз даних, а потім перевірити журнали, щоб побачити, який запит насправді виконує Eloquent, коли ви робите збереження: ви можете бути приємно здивовані
Марк Бейкер

4
Зауважте, що моделі Laravel містять dirtyпрапор, який використовується для визначення того, чи насправді потрібно оновлення бази даних, і цей прапор встановлюється шляхом порівняння вихідних findзначень стовпців зі значеннями в точці, де ви виконуєте збереження
Mark Baker

@MarkBaker Це чудова порада!
user2755140

Відповіді:


177

Ви вже робите це!

save()перевірить, чи не змінилося щось у моделі. Якщо цього не сталося, він не буде запускати запит db.

Ось відповідна частина коду в 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

1
@DaseinA Ви можете використовувати isDirty()для цього. Дивіться оновлену відповідь
lukasgeiter

2
Тим, хто читає це, обов’язково перевірте цю відповідь перед використанням isDirty().
Олексій

1
Є getChanges()метод. Перевірте мій відповідь stackoverflow.com/a/54132163/1090395
Младен Janjetovic

FYI isDirty()буде, trueякщо ви неправильно відкинете свої атрибути. У мене був плаваючий знак, точно такий самий, як і в базі даних, однак, оскільки я встановлював плаваючий рядок (приклад "10.50" замість 10.50), він виявив би це як зміну та здійснив оновлення.
Маартен де Грааф,


11

Я хотів би додати цей метод, якщо ви використовуєте форму редагування, ви можете використовувати цей код, щоб зберегти зміни у вашій update(Request $request, $id)функції:

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

майте на увазі, що ви повинні вводити свої введені однаковою назвою стовпця. fill()Функція буде робити всю роботу за вас :)


3
Це насправді відповідь, яку я шукав, я забув про ім’я fillта як масово передати йому запит. Дякую! Мені не потрібно було передавати посвідчення особи, оскільки я їх оновлюю, тому він уже є $request->id.
бламб
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.