Laravel check if updateOrCreate performed update

点点圈 提交于 2020-06-11 16:51:28

问题


I have the following code in my controller:

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

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

}

each time "updateOrCreate" works, it does 1 of 3 things:

1) updates model instanse OR

2) creates and saves a new one OR

3) leaves everything unchanged (if model with such values already exists).

I need to check if 'updateOrCreate' has done exactly 1 (updated) and then execute some code.

How can I do it?

Thank you in advance!


回答1:


You can figure it out like this:

$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
}

Remarks

In Laravel 5.5 you can finally check if updates have actually taken place with the wasChanged and isDirty method.

  • isDirty() is true if model attribute has been changed and not saved.
  • wasChanged() is true if model attribute has been changed and saved.

There is also a property (not method!) wasRecentlyCreated to check if user was created or not.

$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->vorname = '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('name');
$user->isDirty('name');



回答2:


It is pretty easy to determine if the function resulted in an update or an insert (check the wasRecentlyCreated property). However, when using that function, it is less easy to determine if the update actually happened (if the model exists but is not dirty, no update will be performed). I would suggest not using that function, and splitting out the functionality yourself.

This is the function definition:

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

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

    return $instance;
}

To integrate this into your code, I'd suggest something like:

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



回答3:


@patricus below presented a working way to solve the problem. though @TheFallen here gave a solution which uses Eloquent Events and seems more elegant: Laravel Eloquent Events - implement to save model if Updated




回答4:


The model attribute 'wasRecentlyCreated' would only be 'true' if it has just been created.

There is property named 'changes' in model (it is an array), that determines whether the model has been updated with new values or it has been saved as is without making any changes to its attribute.

Check the following code snippet:

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

            }

        }



回答5:


Okay so I couldn't find a good answer for my scenario.

I was using: $this->created_at == $this->updated_at however I would sometimes update the record later in the request, which meant that 20% of the time the created_at and updated_at were about 1ms out.

To combat this I created something a little more relaxed which allows an extra second between creation and modification.

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

I can now call $this->recentlyCreated which will return true if there is a small difference in time (1 second).

Tbh this is the second time I've needed this in a project, I'm posting as I just ended up googling it and coming back to this thread looking for the same answer.

If someone has a more elegant solution, hmu.



来源:https://stackoverflow.com/questions/45702409/laravel-check-if-updateorcreate-performed-update

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!