Laravel模型事件容许你利用模型生命周期中的各个点,甚至能够防止发生保存或删除。 Laravel 模型事件文档 概述了如何使用事件类来引入这些事件,但本文旨在创建并补充关于设置事件和监听者的一些额外细节。php
Eloquent
有许多事件,你能够将其添加到模型中并添加自定义功能。到目前为止,模型支持的事件以下:laravel
从官方文档中能够看到它们的工做原理,而且你能够跳到基本的Model类中,看看它们是如何工做的:git
当在数据库中一个模型
Model
被检索时,retrieved
事件将触发。 新模型第一次保存时,creating
和created
事件将触发。 若是模型已经存在于数据库中而且调用了save
方法,则updating
/updated
事件将触发。 可是,在这两种状况下,saving
/saved
事件都会触发。github
该文档提供了一个很好的概述,并解释了如何触发这些事件,但若是你是新手或不熟悉如何将事件监听器链接到这些自定义模型事件,请进一步阅读。数据库
为了在模型中关联事件,首先须要使用 $dispatchesEvents
属性来注册事件对象,事件对象最终将经过 HasEvents::fireCustomModelEvent()
方法触发,该方法经过 fireModelEvent()
调用。fireCustomModelEvent()
方法以下所示:bash
/** * Fire a custom model event for the given event. * * @param string $event * @param string $method * @return mixed|null */ protected function fireCustomModelEvent($event, $method) { if (! isset($this->dispatchesEvents[$event])) { return; } $result = static::$dispatcher->$method(new $this->dispatchesEvents[$event]($this)); if (! is_null($result)) { return $result; } }
某些事件(如 delete
)将检查事件是否返回 false
,而后退出操做。例如,你能够使用此hook进行一些检查并防止建立或删除用户。app
以 App\User
模型为例,配置模型事件:框架
protected $dispatchesEvents = [ 'saving' => \App\Events\UserSaving::class, ];
你能够使用 php artisan make:event
命令来建立此事件,UserSaving
类的完整代码以下:ide
<?php namespace App\Events; use App\User; use Illuminate\Queue\SerializesModels; class UserSaving { use SerializesModels; public $user; /** * Create a new event instance. * * @param \App\User $user */ public function __construct(User $user) { $this->user = $user; } }
咱们的事件类提供了一个公共 $user
属性,所以你能够在保存事件期间访问用户模型实例。测试
下面咱们为事件设置一个实际的监听者。当用户模型触发 saving
事件时,监听者被调用,从而容许咱们在事件期间使用模型。
如今咱们的自定义 User
模型事件在保存期间触发,咱们须要为它注册一个监听者。咱们将在一秒钟内使用模型观察者,但我先来看下为单个事件配置事件(Event)和监听列表。
事件监听器就像任何其余Laravel事件监听器同样,handle()
方法将接受 App\Events\UserSaving
事件类的一个实例。
你能够手工建立它,或者使用 php artisan make:listener
命令。可是,你也能够这样建立它,下面是一个建立好的监听者类:
<?php namespace App\Listeners; use App\Events\UserSaving as UserSavingEvent; class UserSaving { /** * Handle the event. * * @param \App\Events\UserSavingEvent $event * @return mixed */ public function handle(UserSavingEvent $event) { app('log')->info($event->user); } }
上面只是给 app('log')->info($event->user);
添加了一个log调用,以便如今能够检查传递给侦听器的模型。为此,咱们须要在 EventServiceProvider::$listen
属性中注册监听器:
<?php namespace App\Providers; use Illuminate\Support\Facades\Event; use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; class EventServiceProvider extends ServiceProvider { /** * The event listener mappings for the application. * * @var array */ protected $listen = [ \App\Events\UserSaving::class => [ \App\Listeners\UserSaving::class, ], ]; // ... }
如今,当模型调度事件时,咱们已注册的侦听器,就能够在 saving
事件期间被调用。
咱们能够使用 tinker
来快速尝试咱们的事件监听器:
php artisan tinker >>> factory(\App\User::class)->create(); => App\User {#794 name: "phpcasts", email: "model_event@phpcasts.org", updated_at: "2018-05-21 13:57:18", created_at: "2018-05-21 13:57:18", id: 2, }
若是你已正确注册了事件和侦听者,则应该在 storage/logs/laravel.log
文件中看到该模型的JSON表示形式:
[2018-05-17 13:57:18] local.INFO: {"name":"phpcasts","email":"model_event@phpcasts.org"}
请注意,此时模型没有 created_at
或 updated_at
属性。 若是你在模型上再次调用 save()
,则日志将具备包含时间戳的新记录,由于 saving
事件会在新建立的记录和现有记录上触发:
>>> $u = factory(\App\User::class)->create(); => App\User {#741 name: "phpcasts", email: "model_event@phpcasts.org", updated_at: "2018-05-21 13:59:37", created_at: "2018-05-21 13:59:37", id: 3, } >>> $u->save(); => true >>>
一些模型事件容许你阻止继续操做。在咱们这个测试的例子中,假设咱们不但愿在 $user->name
属性中保存包含 admin
、root
等名称的用户的模型,则能够这样作:
/** * Handle the event. * * @param \App\Events\UserSaving $event * @return mixed */ public function handle(UserSaving $event) { if (in_array($event->user->name, ['admin', 'root'])) { return false; } }
在基于 Eloquent Model::save()
的方法中,是否会根据此事件处理程序的结果中止保存的事件检查代码:
public function save(array $options = []) { $query = $this->newQueryWithoutScopes(); // If the "saving" event returns false we'll bail out of the save and return // false, indicating that the save failed. This provides a chance for any // listeners to cancel save operations if validations fail or whatever. if ($this->fireModelEvent('saving') === false) { return false; }
save()
方法对于自定义事件如何进入模型生命周期是个比较好的例子,而且能够被动地执行日志数据或派发做业等任务。
若是你正在监听多个事件,则可能会发现使用观察者类将一个类中的多个事件分组更加的方便。如下是来自 Eloquent事件文档 的一个例子:
<?php namespace App\Observers; use App\User; class UserObserver { /** * Listen to the User created event. * * @param \App\User $user * @return void */ public function created(User $user) { // } /** * Listen to the User deleting event. * * @param \App\User $user * @return void */ public function deleting(User $user) { // } }
能够在服务提供者 AppServiceProvider
的 boot()
方法中注册观察者 :
/** * Bootstrap any application services. * * @return void */ public function boot() { User::observe(UserObserver::class); }
事件/监听者 和 观察者均可以达到监听模型事件的做用,体会二者的使用。
能够阅读 Laravel事件文档,以更多地了解事件和监听者如何在整个框架中工做。 Eloquent事件文档 是可用事件以及如何使用观察者的很好参考。 最后,我建议经过浏览 Illuminate\Database\Eloquent\Model
类来查找fireModelEvent()
方法调用的用法,以查看事件如何与模型以及将这些事件组合在一块儿的 HasEvent trait。
更多PHP知识,能够前往 PHPCasts