web-dev-qa-db-ja.com

Laravel updateOrCreateが更新を実行したかどうかを確認します

コントローラに次のコードがあります。

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

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

}

「updateOrCreate」が機能するたびに、3つの処理のうち1つを実行します。

1)モデルのインスタンスを更新OR

2)新しいものを作成して保存するOR

3)すべてを変更しないままにします(そのような値を持つモデルがすでに存在する場合)。

'updateOrCreate'が正確に1(更新済み)を実行したかどうかを確認してから、いくつかのコードを実行する必要があります。

どうすればできますか?

前もって感謝します!

16
Sergej Fomin

Laravel 5.5では、最終的にwasChangedメソッドで実際に更新が行われたかどうかを確認できます

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

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

// If true then tourist has been modified, 
// otherwise either created or not updated 
//
// Note: Before 5.7 it returned only true
// if database entry was modified.
$wasChanged = $tourist->wasChanged();

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

if($wasRecentlyCreated && !$wasChanged){
  // user has just been 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');
28
Adam

関数が更新または挿入を引き起こしたかどうかを判断するのは非常に簡単です(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
patricus

行が更新されたときに常に特定のコードを実行したい場合は、 observer を作成して、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);
}
0
Adam

以下の@patricusは、問題を解決するための有効な方法を示しました。ここで@TheFallenはEloquentイベントを使用してよりエレガントに見えるソリューションを提供しましたが Laravel Eloquentイベント-更新された場合にモデルを保存するための実装

0
Sergej Fomin

モデル属性「wasRecentlyCreated」は、作成されたばかりの場合にのみ「true」になります。

モデル(配列)には 'changes'という名前のプロパティがあり、モデルが新しい値で更新されたか、属性を変更せずにそのまま保存されたかを決定します。

次のコードスニペットを確認してください。

       // 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

            }

        }
0
Naveed Ali