Проверка 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) обновляет модель instanse ИЛИ

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

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

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

Как мне это сделать?

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

Ответ 1

В Laravel 5.5 вы можете наконец проверить, действительно ли обновления выполнялись с wasChanged метода wasChanged

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

// If true then created otherwise maybe updated
$wasCreated = $tourist->wasRecentlyCreated; 

// If true then the row in the database has been modified, 
// otherwise either created or not updated
$wasChanged = $tourist->wasChanged();

if(!$wasCreated && $wasChanged){
  // user existed and there were actually updates taking place.
}

if($wasCreated && !$wasChanged){
  // user was created. The row wasn't updated after creation.
}

// If true then the object '$tourist' has been modified but not saved
$tourist->isDirty();

//You can also check if a specific attribute was changed:
$tourist->wasChanged('name');
$tourist->isDirty('name');

Ответ 2

Достаточно легко определить, вызвала ли функция обновление или вставку (проверьте свойство 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
    }
}

Ответ 4

Если вы хотите всегда выполнять определенный код при обновлении строки, я бы рекомендовал создать наблюдателя для прослушивания updated или create вызовов.

<?php

namespace App\Observers;

use App\Tourist;

class TouristObserver
{
    /**
     * Listen to the User created event.
     *
     * @param  \App\User  $user
     * @return void
     */
    public function created(Tourist $user)
    {
        // this will always trigger when you created a new entry
    }

    /**
     * Listen to the User deleting event.
     *
     * @param  \App\Tourist $user
     * @return void
     */
    public function updated(Tourist $user)
    {
        // this will always trigger when actually a row was updated
    }
}

Все, что вам нужно сделать, это зарегистрировать наблюдателя в AppServiceProvider следующим образом:

public function boot()
{
    Tourist::observe(\App\Observer\TouristObserver::class);
}