Laravel проверяет, выполнил ли updateOrCreate обновление

В моем контроллере есть следующий код:

for($i=0; $i<$number_of_tourists; $i++) {

$tourist = Tourist::updateOrCreate(['doc_number' => $request['doc_number'][$i]],
$tourist_to_update);

}

Каждый раз, когда срабатывает updateOrCreate, он выполняет 1 из 3 действий:

1) обновляет экземпляр модели ИЛИ

2) создает и сохраняет новый ИЛИ

3) оставляет все без изменений (если модель с такими значениями уже существует).

Мне нужно проверить, выполнил ли updateOrCreate ровно 1 (обновлено), а затем выполнить некоторый код.

Как я могу это сделать?

Заранее спасибо!


person Sergej Fomin    schedule 15.08.2017    source источник
comment
Можете ли вы использовать событие модели updated (срабатывает только при фактическом обновлении модели) или этот дополнительный код следует запускать только тогда, когда этот конкретный набор кода обновляет модель?   -  person patricus    schedule 16.08.2017
comment
@patricus, спасибо! Я использовал событие обновленной модели, но мне удалось сделать это только для некоторых простых вещей, таких как дескриптор публичной функции (TouristUpdated $ event) {dump ($ event); } (это код моего слушателя). Я не могу понять, как я могу проинструктировать слушателя добавить некоторую логику в мой контроллер. На самом деле логика должна заключаться в создании массива всех $ tourist_to_update ', которые инициировали событие updated'. Надеюсь, я ясно объяснил.   -  person Sergej Fomin    schedule 16.08.2017


Ответы (5)


Разобраться можно так:

$tourist = Tourist::updateOrCreate([...]);

if(!$tourist->wasRecentlyCreated && $tourist->wasChanged()){
    // updateOrCreate performed an update
}

if(!$tourist->wasRecentlyCreated && !$tourist->wasChanged()){
    // updateOrCreate performed nothing, row did not change
}

if($tourist->wasRecentlyCreated){
   // updateOrCreate performed create
}

Примечания

Начиная с Laravel 5.5 и выше, вы можете проверить, действительно ли происходили обновления, с помощью методов wasChanged и isDirty.

  • isDirty() истинно, если атрибут модели был изменен, но не сохранен.
  • wasChanged() истинно, если атрибут модели был изменен и сохранен.

Также есть свойство (не метод!) wasRecentlyCreated для проверки, создан ли пользователь или нет.

$user = factory(\App\User::class)->create();

$user->wasRecentlyCreated; // true
$user->wasChanged(); // false
$user->isDirty(); // false

$user = \App\User::find($user->id);

$user->wasRecentlyCreated; // false
$user->wasChanged(); // false
$user->isDirty(); // false

$user->firstname = 'Max';

$user->wasChanged(); // false
$user->isDirty(); // true

$user->save();

$user->wasChanged(); // true
$user->isDirty(); // false

//You can also check if a specific attribute was changed:
$user->wasChanged('firstname');
$user->isDirty('firstname');
person Adam    schedule 18.03.2018

Довольно легко определить, привела ли функция к обновлению или вставке (проверьте свойство wasRecentlyCreated). Однако при использовании этой функции труднее определить, действительно ли произошло обновление (если модель существует, но не загрязнена, обновление выполняться не будет). Я бы посоветовал не использовать эту функцию и разделить ее самостоятельно.

Это определение функции:

public function updateOrCreate(array $attributes, array $values = [])
{
    $instance = $this->firstOrNew($attributes);

    $instance->fill($values)->save();

    return $instance;
}

Чтобы интегрировать это в свой код, я бы предложил что-то вроде:

for ($i=0; $i<$number_of_tourists; $i++) {
    $tourist = Tourist::firstOrNew(['doc_number' => $request['doc_number'][$i]]);

    $tourist->fill($tourist_to_update);

    // if the record exists and the fill changed data, update will be performed
    $updated = $tourist->exists && $tourist->isDirty();

    // save the tourist (insert or update)
    $tourist->save();

    if ($updated) {
        // extra code
    }
}
person patricus    schedule 15.08.2017
comment
спасибо! Я уже думал об этом, но вы подробно объяснили это. Я все еще надеюсь, что есть шанс использовать «обновленное» модельное событие. А если нет - я выберу этот ответ как «правильный». - person Sergej Fomin; 16.08.2017
comment
Не могли бы вы объяснить свое первое послание It is pretty easy to determine if the function resulted in an update or an insert.? Потому что это все, что я хочу, и не знаю, как этого добиться. - person Adam; 08.02.2018
comment
NVM Я его уже нашел: stackoverflow.com/questions/44238257/ - person Adam; 08.02.2018
comment
@ Адам Рад, что ты его нашел. Я пошел дальше и обновил свой ответ, чтобы упомянуть об этом, на случай, если кто-то еще придет сюда и задается вопросом. Спасибо. - person patricus; 08.02.2018
comment
Теперь есть функция с именем wasChanged(), которая выполняет эту работу. - person Adam; 18.03.2018

Хорошо, я не смог найти хорошего ответа для своего сценария.

Я использовал: $this->created_at == $this->updated_at, однако иногда я обновлял запись позже в запросе, что означало, что в 20% случаев created_at и updated_at были примерно на 1 мс.

Чтобы бороться с этим, я создал что-то более расслабленное, что дает дополнительную секунду между созданием и модификацией.

public function getRecentlyCreatedAttribute()
{
    return $this->wasRecentlyCreated || $this->created_at == $this->updated_at || $this->created_at->diffInSeconds($this->updated_at) <= 1;
}

Теперь я могу вызвать $this->recentlyCreated, который вернет истину, если есть небольшая разница во времени (1 секунда).

Tbh, это второй раз, когда мне это нужно в проекте, я публикую, поскольку я только что закончил поиск в Google и вернулся в эту ветку в поисках того же ответа.

Если у кого-то есть более изящное решение, хму.

person Jera    schedule 20.05.2020

@patricus ниже представил рабочий способ решения проблемы. хотя @TheFallen здесь дал решение, которое использует Eloquent Events и кажется более элегантным: Laravel Eloquent Events - реализовать для сохранения модели при обновлении

person Sergej Fomin    schedule 16.08.2017

Атрибут модели wasRecentlyCreated будет иметь значение true, только если он только что был создан.

В модели есть свойство с именем «изменения» (это массив), которое определяет, была ли модель обновлена ​​новыми значениями или она была сохранена как есть без внесения каких-либо изменений в ее атрибут.

Проверьте следующий фрагмент кода:

       // Case 1 :  Model Created
        if ($model->wasRecentlyCreated) {

        } else { // Case 2 :  Model Updated

            if (count($model->changes)) { // model has been assigned new values to one of its attributes and saved successfully

            } else { // model has NOT been assigned new values to one of its attributes and saved as is

            }

        }
person Naveed Ali    schedule 30.10.2019