问题
I have such code in the controller:
for($i=0; $i<$number_of_tourists; $i++) {
$tourist = Tourist::updateOrCreate(['doc_number' => $request['doc_number'][$i]],
$tourist_to_update);
}
so, the updateOrCreate method can 1) Update record, 2) Create a new one 3) Leave record untouched if $tourist_to_update equals to what's already in the DB.
I want to save $tourist_to_update into $array[] only when a record in 'tourist" table is being updated (not when a new record created or nothing changes).
As I know, there are Eloquent events https://laravel.com/docs/5.4/eloquent#events which have updating and updated events, which seem to match my needs.
The problem is I watched&read several tutorials and still don't understand how to use them.
I know how-to-register a Eloquent event in Tourist model:
protected static function boot()
{
parent::boot();
static::updating(function ($model) {
});
}
Could anyone explain how can I achive my goal with Eloquent events?
Thank you in advance.
回答1:
This is a bit more complex approach, but if you want to get only updated records which have their data changed this is working. In your controller method add:
app()->singleton('touristsCollector', function ($app) {
$collector = new \stdClass;
$collector->updated = [];
return $collector;
});
for($i = 0; $i < $number_of_tourists; $i++) {
$tourist = Tourist::updateOrCreate(
['doc_number' => $request['doc_number'][$i]],
$tourist_to_update
);
}
$collector = resolve('touristsCollector');
var_dump( $collector->updated ); // Only updated tourists which have data changed
This will basically add to the app container a standard PHP class which will collect all the updated tourists from the model event. In your model add this:
protected static function boot()
{
parent::boot();
static::updated(function ($model) {
$collector = resolve('touristsCollector');
$collector->updated[] = $model;
});
}
This will basically get the PHP class from the app container add the tourist model only if some properties of it have been updated.
回答2:
If the model has been created the property wasRecentlyCreated
will be set to true, so this is how you can check if the model is new or updated:
$updated = [];
for($i = 0; $i < $number_of_tourists; $i++) {
$currentTourist = ['doc_number' => $request['doc_number'][$i]];
$tourist = Tourist::updateOrCreate($currentTourist, $tourist_to_update);
if ( $tourist->wasRecentlyCreated ) {
continue; // Go to next loop if this tourist was created now
}
$updated[] = $tourist;
}
回答3:
If you always want to execute a specific code when a row in tourist table was updated, I would recommend to create an observer to listen for updated
or create
calls.
<?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
}
}
All you have to do is to register the observer in AppServiceProvider
like this:
public function boot()
{
Tourist::observe(\App\Observer\TouristObserver::class);
}
来源:https://stackoverflow.com/questions/45698659/laravel-eloquent-events-implement-to-save-model-if-updated