>

模型事件学习笔记,Laravel模型事件的落到实处原

- 编辑:www.bifa688.com -

模型事件学习笔记,Laravel模型事件的落到实处原

先是我们来看看这些被誉为 模型事件(model events) 的技术。它的基本概念特别轻巧:

Laravel模型事件的实现原理详解,laravel模型

前言

Laravel的ORM模型在有些一定的情况下,会接触一名目好些个的平地风波,近日支撑的事件有那个:creating, created, updating, updated, saving, saved, deleting, deleted, restoring, restored,那么在底层是如何达成这几个意义的吧?

上边话相当少说了,来共同拜访详细的牵线吧。

1.什么样行使模型事件

先来拜访哪些运用模型事件,文书档案里面写了二种艺术,实际上海市总共有三种艺术得以定义四个模子事件,这里以saved事件来做例子,其余事件都一样。

1.events属性

直白上代码:

class User extends Authenticatable {
 use Notifiable;

 protected $events = [
  'saved' => UserSaved::class,
 ];
}

本条比较为难精晓,何况文书档案并不曾详细表达,刚起始以为saved被触发后会调用UserSaved里面包车型大巴handle方法,实际上实际不是。那一个数组只是对事件做的贰个璀璨,它定义了在模型的saved的时候会触发UserSaved这些事件,大家还要定义该事件以及其监听器才得以:

namespace AppEvents;
use AppUser;
class UserSaved {
 public $user;
 public function __construct(User $user){
  $this->user = $user;
 }
}

namespace AppListeners;
class UserSavedListener {
 public function handle(UserSaved $userSaved){
  dd($userSaved);
 }
}

接下来还要到EventServiceProvider中去注册该事件和监听器:

class EventServiceProvider extends ServiceProvider
{
 /**
  * The event listener mappings for the application.
  *
  * @var array
  */
 protected $listen = [
  'AppEventsUserSaved' => [
   'AppListenersUserSavedListener',
  ]
 ];

 /**
  * Register any events for your application.
  *
  * @return void
  */
 public function boot()
 {
  parent::boot();
 }
}

那般在saved节点的时候,UserSaved事件会被触发,其监听器UserSavedListener的handle方法会被调用。

2.观察者

那是文档相比较正视的三个模型事件定义方法,也相比好掌握,先定义三个观望者:

use AppUser;
class UserObserver
{
 /**
  * 监听用户创建事件.
  *
  * @param User $user
  * @return void
  */
 public function created(User $user)
 {
  //
 }

 /**
  * 监听用户创建/更新事件.
  *
  * @param User $user
  * @return void
  */
 public function saved(User $user)
 {
  //
 }
}

接下来在有个别服务提供者的boot方法中登记观看者:

namespace AppProviders;
use AppUser;
use AppObserversUserObserver;
use IlluminateSupportServiceProvider;
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()
 {
  //
 }
}

那样在模型事件触发的时候,UserObserver的相应措施就能够被调用。其实,在采取观察者的时候,除了有的系统自带的,我们还足以定义一些温馨的事件:

class User extends Authenticatable {
 use Notifiable;
 protected $observables = [
  'customing', 'customed'
 ];
}

下一场在阅览者里面定义同名方法:

class UserObserver
{
 /**
  * 监听用户创建/更新事件.
  *
  * @param User $user
  * @return void
  */
 public function saved(User $user)
 {
  //
 }

 public function customing(User $user){
 }

  public function customed(User $user){
 }
}

鉴于是我们团结定义的事件,所以触发的时候也非得手动触发,在急需接触的地点调用模型里面的一个fireModel伊夫nt方法就能够。然则由于该办法是protected的,所以只好在和睦定义的模型方法里面,当然假使经过反射来调用,或者能够一贯在$user对象上接触也恐怕,那么些自个儿没试,大家能够活动测量试验下。

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

3.静态方法定义

咱俩还足以因此模型上的照望静态方法来定义三个事件,在EventServiceProvider的boot方法里面定义:

class EventServiceProvider extends ServiceProvider{
 /**
  * Register any events for your application.
  *
  * @return void
  */
 public function boot()
 {
  parent::boot();
  User::saved(function(User$user) {
  });
  User::saved('[email protected]');
 }
}

经过静态方法定义的时候,能够一贯传送进入一个闭包,也足以定义为有些类的秘籍,事件触发时候传递步入的参数便是该模型实例。

2.模型事件达成原理

Laravel的模型事件有所的代码都在IlluminateDatabaseEloquentConcernsHasEvents那个trait下,先来拜候Laravel是何等注册那几个事件的,个中的$dispatcher是四个风浪的调治器IlluminateContractsEventsDispatcher实例,在IlluminateDatabaseDatabase瑟维斯Provider的boot方法中流入。

protected static function registerModelEvent($event, $callback){
  if (isset(static::$dispatcher)) {
   $name = static::class;
   static::$dispatcher->listen("eloquent.{$event}: {$name}", $callback);
  }
 }

此间是Laravel事件注册的地点,个中以eloquent.saved:AppUser为事件名,$callback作为管理器来注册。这么些注册事件的章程,只会登记以观看者和静态方法定义的。假诺你定义为模型的$events属性的话,Laravel是不会登记的,会在触及事件的时候共同触发,接下去会深入分析。

下一场在Has伊夫nts中定义了一群的点子如下,那些正是大家地点通过静态方法来定义事件监听器的原理,相当少说一看就懂。

public static function saving($callback){
 static::registerModelEvent('saving', $callback);
}

public static function saved($callback){
 static::registerModelEvent('saved', $callback);
}

那正是说什么样通过观看者的款式来定义事件监听器呢?看源码:

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

先拿走到observer的类名,然后判别是不是存在事件名对应的点子,存在则调用registerModelEvent注册,这里事件名还包罗大家本人定义在observables数组中的。

事件以及监听器都定义好后,正是什么触发了,前边聊到有贰个措施fireModel伊芙nt,来会见源码:

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

个中拾分主要的三个主意是fireCustomModelEvent,它接受二个事变名以及触发情势。顺带一提,filterModelEventResults那一个办法的效用就是把监听器的再次回到值为null的过滤掉。

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

以此正是用来触发大家因此$events定义的事件了,借使大家那样定义:

class User extends Model{
 protected $events = [
  'saved' => UserSaved::class
 ]
}

那这里的接触就是:

 $result = static::$dispatcher->fire(new UserSaved($this));

顺带一提,Laravel中触发事件的形式有多少个,三个是常用的fire,还会有一个是util,那八个的出入正是fire会把监听器的重回值重返,而util恒久重返null

接下来接下去就是会去接触通过观看者和静态方法定义的监听器了,这一段代码:

  if ($result === false) {
   return false;
  }

  return ! empty($result) ? $result : static::$dispatcher->{$method}(
   "eloquent.{$event}: ".static::class, $this
  );

此处会先判别$events定义的监听器是或不是重回false以及再次来到值是还是不是为空,若是为false则直接截止事件,假使回到不为false而且为空的话,会再去接触通过阅览者和静态方法定义的监听器,况兼把监听器的重临值重返。
完。

总结

以上正是那篇作品的全部内容了,希望本文的剧情对大家的就学只怕干活有着一定的参照他事他说加以考察学习价值,如若有疑问我们能够留言交流,多谢大家对帮客之家的支撑。

前言 Laravel的ORM模型在部分特定的事态下,会接触一层层的风云,前段时间支撑的风云有这几个:crea...

前言

在 伊芙ntServiceProvider 中您能够增多多个一定的事件监听器,并绑定二个闭包函数
在闭包函数中,你无需接触模型代码就能够加多新的一言一行
绑定操作必须放在类的 boot() 方法中

Laravel的ORM模型在部分特定的情景下,会接触一多重的风云,近日支撑的风云有这个:creating, created, updating, updated, saving, saved, deleting, deleted, restoring, restored,那么在底层是如何落到实处这么些效应的吗?

那是二个把创设 (created) 用户事件与闭包函数进行绑定的简易示例。闭包的 $user 参数包括了点名用户的实例:

下边话非常的少说了,来一齐拜望详细的介绍吧。

  public function boot(DispatcherContract $events)
  {
      parent::boot($events);
 
      User::created(function($user)
      {
          // doing something here, after User creation...
      });
  }

1.什么使用模型事件

正如您想像的,每四个模型都有这一个方法,所以,假如您想为 saved 事件绑定三个操作的话,你无法不:

先来探视怎么样使用模型事件,文书档案里面写了两种格局,实际上海市中华全国总工会共有二种方法能够定义二个模型事件,这里以saved事件来做例子,其余事件都一律。

    User::saved(function($user)
    {
        // doing something here, after User save operation (both create and update)...
    });

1.events属性

其它一个有趣的效果是能够透过预方法甘休当前操作。事实上,你大概会用到下边包车型大巴主意:

一贯上代码:

creating
updating
saving
restoring
deleting

class User extends Authenticatable {
 use Notifiable;

 protected $events = [
  'saved' => UserSaved::class,
 ];
}

要是你想退出操作的话,能够回来贰个布尔类型的 false 值。

以此比较为难驾驭,而且文书档案并不曾详尽表明,刚初始感到saved被触发后会调用UserSaved里面包车型地铁handle方法,实际上而不是。那些数组只是对事件做的一个炫人眼目,它定义了在模型的saved的时候会触发UserSaved这几个事件,大家还要定义该事件以及其监听器才方可:

借使用户邮箱以 @deniedprovider.com 结尾的话,我们就退出 create 操作,能够如此做:

namespace AppEvents;
use AppUser;
class UserSaved {
 public $user;
 public function __construct(User $user){
  $this->user = $user;
 }
}


namespace AppListeners;
class UserSavedListener {
 public function handle(UserSaved $userSaved){
  dd($userSaved);
 }
}

    User::creating(function($user)
    {
      if(ends_with($user->email, '@deniedprovider.com'))
      {
        return false;
      }
    });

然后还要到伊芙ntServiceProvider中去挂号该事件和监听器:

很鲜明,对于 created, updated, saved, restored, 和 deleted 事件则不可能如此做,那几个事件早就发出了,不可能回去。

class EventServiceProvider extends ServiceProvider
{
 /**
  * The event listener mappings for the application.
  *
  * @var array
  */
 protected $listen = [
  'AppEventsUserSaved' => [
   'AppListenersUserSavedListener',
  ]
 ];

 /**
  * Register any events for your application.
  *
  * @return void
  */
 public function boot()
 {
  parent::boot();
 }
}

如此在saved节点的时候,UserSaved事件会被触发,其监听器UserSavedListener的handle方法会被调用。

2.观察者

那是文书档案相比较重视的三个模子事件定义方法,也相比好理解,先定义三个观望者:

use AppUser;
class UserObserver
{
 /**
  * 监听用户创建事件.
  *
  * @param User $user
  * @return void
  */
 public function created(User $user)
 {
  //
 }

 /**
  * 监听用户创建/更新事件.
  *
  * @param User $user
  * @return void
  */
 public function saved(User $user)
 {
  //
 }
}

然后在有个别服务提供者的boot方法中登记观看者:

namespace AppProviders;
use AppUser;
use AppObserversUserObserver;
use IlluminateSupportServiceProvider;
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()
 {
  //
 }
}

如此那般在模型事件触发的时候,UserObserver的对应措施就能被调用。其实,在采取观察者的时候,除了部分系统自带的,我们还能定义一些和谐的风云:

class User extends Authenticatable {
 use Notifiable;
 protected $observables = [
  'customing', 'customed'
 ];
}

接下来在观望者里面定义同名方法:

class UserObserver
{
 /**
  * 监听用户创建/更新事件.
  *
  * @param User $user
  * @return void
  */
 public function saved(User $user)
 {
  //
 }

 public function customing(User $user){
 }

  public function customed(User $user){
 }
}

鉴于是我们团结定义的风云,所以触发的时候也无法不手动触发,在急需接触的地方调用模型里面的叁个fireModelEvent方法就可以。然而由于该方法是protected的,所以只可以在协调定义的模子方法里面,当然要是因而反射来调用,大概能够一向在$user对象上接触也恐怕,那个自家没试,我们能够活动测量试验下。

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

3.静态方法定义

我们还足以由此模型上的附和静态方法来定义贰个事件,在伊芙ntServiceProvider的boot方法里面定义:

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');
 }
}

通过静态方法定义的时候,能够一贯传送走入多个闭包,也足以定义为有个别类的章程,事件触发时候传递进入的参数正是该模型实例。

2.模型事件完成原理

Laravel的模型事件负有的代码都在IlluminateDatabaseEloquentConcernsHasEvents那个trait下,先来会见Laravel是怎么注册那个事件的,个中的$dispatcher是三个事变的调解器IlluminateContractsEventsDispatcher实例,在IlluminateDatabaseDatabaseServiceProvider的boot方法中流入。

protected static function registerModelEvent($event, $callback){
  if (isset(static::$dispatcher)) {
   $name = static::class;
   static::$dispatcher->listen("eloquent.{$event}: {$name}", $callback);
  }
 }

此处是Laravel事件注册的地点,当中以eloquent.saved:AppUser为事件名,$callback作为管理器来注册。那个注册事件的措施,只会登记以观察者和静态方法定义的。如若你定义为模型的$events属性的话,Laravel是不会登记的,会在触及事件的时候一齐触发,接下去会深入分析。

下一场在Has伊夫nts中定义了一群的主意如下,那么些正是大家地点通过静态方法来定义事件监听器的原理,十分少说一看就懂。

public static function saving($callback){
 static::registerModelEvent('saving', $callback);
}

public static function saved($callback){
 static::registerModelEvent('saved', $callback);
}

那么哪些通过观望者的样式来定义事件监听器呢?看源码:

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

先获得到observer的类名,然后判别是不是留存事件名对应的主意,存在则调用registerModel伊夫nt注册,这里事件名还包涵大家自个儿定义在observables数组中的。

事件以及监听器都定义好后,正是何等触发了,前边聊到有一个办法fireModel伊夫nt,来看看源码:

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

在那之中相比首要的二个格局是fireCustomModelEvent,它接受一个事件名以及触发方式。顺带一提,filterModel伊芙ntResults那些法子的作用正是把监听器的重返值为null的过滤掉。

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

其一正是用来触发我们透过$events定义的事件了,就算大家这么定义:

class User extends Model{
 protected $events = [
  'saved' => UserSaved::class
 ]
}

那这里的接触正是:

 $result = static::$dispatcher->fire(new UserSaved($this));

顺带一提,Laravel中触发事件的措施有七个,三个是常用的fire,还也可能有一个是util,那七个的歧异正是fire会把监听器的重返值重临,而util永世再次来到null

接下来接下去正是会去接触通过阅览者和静态方法定义的监听器了,这一段代码:

  if ($result === false) {
   return false;
  }

  return ! empty($result) ? $result : static::$dispatcher->{$method}(
   "eloquent.{$event}: ".static::class, $this
  );

那边会先剖断$events定义的监听器是还是不是重回false以及重回值是不是为空,假使为false则直接截止事件,假如回到不为false并且为空的话,会再去接触通过观看者和静态方法定义的监听器,而且把监听器的重返值再次回到。
完。

总结

以上便是那篇作品的全体内容了,希望本文的故事情节对我们的读书也许干活有着一定的参谋学习价值,借使有疑难大家能够留言交流,谢谢大家对台本之家的支撑。

你或者感兴趣的稿子:

  • 跟笔者学Laravel之央浼(Request)的生命周期
  • Laravel 5框架学习之模型、调节器、视图基础流程
  • 跟作者学Laravel之乞求与输入
  • Laravel 5.5中为响应央浼提供的可响接待口详解
  • Laravel 5.4再一次登陆完成跳转到登陆前页面包车型地铁规律和方法
  • Laravel中间件达成原理详解
  • 浅谈Laravel队列完毕原理消除难点记录
  • Laravel中Facade的加载进度与原理详解
  • Laravel框架生命周期与原理剖判

本文由必发88手机版发布,转载请注明来源:模型事件学习笔记,Laravel模型事件的落到实处原