Eloquent Model Events The entire Laravel world is Eloquent, most operations for you will trigger some kind of model event, Eloquent at one point or another.
preface
Laravel’s ORM model will trigger a series of events under certain circumstances. These events are currently supported: Creating, created, updating, updated, saving, saved, deleting, deleted, Restoring, restored, restored.
Without further ado, let’s take a look at the detailed introduction.
1. How are model events used
So let’s take a look at how to use model events. There are two ways in the documentation, but there are actually three ways to define a model event, so let’s use the saved event as an example, everything else is the same.
1. The events attributes
Directly on the code:
class User extends Authenticatable {
use Notifiable;
protected $events = [
'saved' => UserSaved::class,
];
}
Copy the code
This array is just a mapping of the event that defines the UserSaved event to be fired when the model saved. We need to define the event and its listener:
amespace App\Events; use App\User; class UserSaved { public $user; public function __construct(User $user){ $this->user = $user; } } namespace App\Listeners; class UserSavedListener { public function handle(UserSaved $userSaved){ dd($userSaved); }}Copy the code
Then register the event and listener in the EventServiceProvider:
class EventServiceProvider extends ServiceProvider { /** * The event listener mappings for the application. * * @var array */ protected $listen = [ 'App\Events\UserSaved' => [ 'App\Listeners\UserSavedListener', ] ]; /** * Register any events for your application. * * @return void */ public function boot() { parent::boot(); }}Copy the code
The saved event will be raised and the handle method of its listener, UserSavedListener, will be called.
2. The observer
This is an approach to model event definition that is well documented and well understood. First define an observer:
use App\User; ** @param User $User * @return void */ public function created(User $User) {// ** @param User $User * @return void */ public function saved(User $User) {//Copy the code
Then register the observer in a service provider’s boot method:
namespace App\Providers;
use App\User;
use App\Observers\UserObserver;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
User::observe(UserObserver::class);
}
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
//
}
}
Copy the code
When a model event is triggered, the corresponding method of UserObserver will be called. In addition to some of the system’s built-in events, we can also define our own events when using observers:
class User extends Authenticatable {
use Notifiable;
protected $observables = [
'customing', 'customed'
];
}
Copy the code
Then define the same method in the observer:
** @param User $User * @return void */ public function saved(User $User) {//} public function customing(User $user){ } public function customed(User $user){ } }Copy the code
Since it is an event defined by ourselves, we must manually trigger it when it is triggered. We can call a fireModelEvent method in the model where it needs to be triggered. However, since this method is protected, it can only be used in the model method defined by you, although if it is called by reflection, it can be triggered directly on the $user object. I haven’t tried this, but you can test it yourself.
class User extends Authenticatable { use Notifiable; protected $observables = [ 'customing', 'awesoming' ]; public function custom(){ if ($this->fireModelEvent('customing') === false) { return false; } //TODO if ($this->fireModelEvent('customed') === false) { return false; }}}Copy the code
Static method definition
We can also define an event using the corresponding static method on the model, in the EventServiceProvider boot method:
class EventServiceProvider extends ServiceProvider{ /** * Register any events for your application. * * @return void */ public function boot() { parent::boot(); User::saved(function(User$user) { }); User::saved('UserSavedListener@saved'); }}Copy the code
When defined through a static method, it can be passed directly into a closure, or it can be defined as a method of a class, and the parameters passed in when the event is triggered are the model instance.
2. Realization principle of model events
All of the code for Laravel’s model events is placed under the Illuminate\Database\Eloquent\Concerns\HasEvents trait. Let’s start by looking at how Laravel registers these events. Where $Dispatcher is an instance of the event scheduler, Illuminate\Contracts\Events\Dispatcher, injected into the Illuminate\Database\DatabaseServiceProvider’s boot method.
protected static function registerModelEvent($event, $callback){ if (isset(static::$dispatcher)) { $name = static::class; static::$dispatcher->listen("eloquent.{$event}: {$name}", $callback); }}Copy the code
This is where the Laravel event is registered, eloquent. Saved :App\User as the event name and callback as the handler. The method that registers events will only register observer and static methods defined. Suppose the callback you define as a model is registered as a handler. The method that registers events will only register observer and static methods defined. Suppose the callback you define as a model is registered as a handler. The method that registers events will only register observer and static methods defined. If you define the events property of the model, Laravel will not be registered and will be fired synchronously when the event is fired, which will be analyzed next.
We then define a bunch of methods in HasEvents as follows. This is how we define event listeners using static methods above.
public static function saving($callback){
static::registerModelEvent('saving', $callback);
}
public static function saved($callback){
static::registerModelEvent('saved', $callback);
}
Copy the code
So how do you define event listeners in the form of observers? See the source code:
public static function observe($class){
$instance = new static;
$className = is_string($class) ? $class : get_class($class);
foreach ($instance->getObservableEvents() as $event) {
if (method_exists($class, $event)) {
static::registerModelEvent($event, $className.'@'.$event);
}
}
}
public function getObservableEvents()
{
return array_merge(
[
'creating', 'created', 'updating', 'updated',
'deleting', 'deleted', 'saving', 'saved',
'restoring', 'restored',
],
$this->observables
);
}
Copy the code
Obtain the name of the observer class, and then check whether there is a method corresponding to the event name. If so, call registerModelEvent to register the event name, which is also included in the observables array we defined ourselves.
Events and listeners are defined, and how to trigger them is a function of the remodeling event.
protected function fireModelEvent($event, $halt = true)
{
if (! isset(static::$dispatcher)) {
return true;
}
$method = $halt ? 'until' : 'fire';
$result = $this->filterModelEventResults(
$this->fireCustomModelEvent($event, $method)
);
if ($result === false) {
return false;
}
return ! empty($result) ? $result : static::$dispatcher->{$method}(
"eloquent.{$event}: ".static::class, $this
);
}
Copy the code
One of the more critical methods is fireCustomModelEvent, which takes an event name and how it is triggered. The filterModelEventResults method, by the way, filters out listeners that return null.
See the source code for fireCustomModelEvent:
protected function fireCustomModelEvent($event, $method) { if (! isset($this->events[$event])) { return; } $result = static::$dispatcher->$method(new $this->events[$event]($this)); if (! is_null($result)) { return $result; }}Copy the code
This is the event that triggers our definition of $events, if we define it this way:
class User extends Model{
protected $events = [
'saved' => UserSaved::class
]
}
Copy the code
The trigger here is:
$result = static::$dispatcher->fire(new UserSaved($this));
Copy the code
By the way, there are two methods in Laravel that trigger events, the common fire method and util method. The difference between the two methods is that fire returns the listener’s return value, while util always returns null
The listener defined by observer and static methods is triggered:
if ($result === false) {
return false;
}
return ! empty($result) ? $result : static::$dispatcher->{$method}(
"eloquent.{$event}: ".static::class, $this
);
Copy the code
If it is false, the event is terminated. If it is not false and is null, the listener defined by the observer and static method is fired and the listener’s return value is returned.
I hope the above content can help you. Many PHPer will encounter some problems and bottlenecks when they are advanced, and they have no sense of direction when writing too many business codes. I have sorted out some information, including but not limited to: Distributed architecture, high scalability, high performance, high concurrency, server performance tuning, TP6, Laravel, Redis, Swoft, Kafka, Mysql optimization, shell scripting, Docker, microservices, Nginx, etc. Many knowledge points can be free to share with you