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 to use model events First let’s look at how to use model events. There are two ways to define a model event.

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;
class UserObserver
{
 /** * listen for user creation events. **@param User $user
  * @return void
  */
 public function created(User $user)
 {
  //
 }
 
 /** * listen for user creation/update events. **@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:

class UserObserver
{
 /** * listen for user creation/update events. **@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.

All the code for Laravel’s model events is placed under the Illuminate\Database\Eloquent\Concerns\HasEvents trait. Let’s take a look 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.The '@'.$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