在 Eloquent 模型類上進行查詢、插入、更新、刪除操做時,會觸發相應的模型事件,無論你有沒有監聽它們。這些事件包括:php
retrieved | 獲取到模型實例後觸發 |
creating | 插入到數據庫前觸發 |
created | 插入到數據庫後觸發 |
updating | 更新到數據庫前觸發 |
updated | 更新到數據庫後觸發 |
saving | 保存到數據庫前觸發(插入/更新以前,不管插入仍是更新都會觸發) |
saved | 保存到數據庫後觸發(插入/更新以後,不管插入仍是更新都會觸發) |
deleting | 從數據庫刪除記錄前觸發 |
deleted | 從數據庫刪除記錄後觸發 |
restoring | 恢復軟刪除記錄前觸發 |
restored | 恢復軟刪除記錄後觸發 |
注:批量更新時不會觸發相應事件,由於是直接走查詢構建器完成的,繞過了模型方法。laravel
經過監聽這些事件,咱們能夠在 Eloquent 模型實例生命週期的特定階段執行特定操做。在 Laravel 中咱們有多種方式來監聽模型事件。數據庫
經過在模型類上調用要監聽事件對應的靜態方法,通常咱們會在某個服務提供者的 boot
方法中完成這項工做,好比 EventServiceProvider
。舉個例子,假設咱們要監聽每次獲取模型實例的事件並在日誌中記錄查詢到的用戶信息,能夠這麼作:閉包
// app/Providers/EventServiceProvider.php public function boot() { parent::boot(); // 監聽模型獲取事件 User::retrieved(function ($user) { Log::info('從模型中獲取用戶[' . $user->id . ']:' . $user->name); }); }
上面這段代碼中表示咱們在 User
模型上監聽 retrieved
事件,而後經過一個閉包函數執行對應的處理邏輯,該閉包函數傳入參數是模型實例,在處理邏輯中,咱們經過 Log
門面記錄日誌信息。app
以刪除模型爲例進行演示,分別定義一個刪除前事件類和刪除後事件類。咱們經過 Artisan 命令來完成事件類初始化:ide
php artisan make:event UserDeleting php artisan make:event UserDeleted
而後在這兩個事件類中都添加 $user
屬性並在構造函數中傳入:函數
// app/Events/UserDeleted.php // app/Events/UserDeleting.php public $user; public function __construct(User $user) { $this->user = $user; }
在 User
模型類中創建模型事件與自定義事件類的映射,這能夠經過 $dispatchesEvents
屬性來完成:this
//創建模型事件與自定義事件類的映射 protected $dispatchesEvents = [ 'deleting' => UserDeleting::class, 'deleted' => UserDeleted::class ];
這樣,當咱們觸發 deleting
和 deleted
事件時,底層會將其轉化爲觸發 UserDeleting
和 UserDeleted
事件。spa
咱們還要監聽上述自定義的事件類,咱們能夠經過在 EventServiceProvider
的 listen
屬性中爲每一個事件綁定對應的監聽器類,也能夠經過爲某個模型類建立一個事件訂閱者類來統一處理該模型中的全部事件。在 app/Listeners
目錄下建立一個 UserEventSubscriber.php
文件做爲訂閱者類,編寫代碼以下rest
<?php namespace App\Listeners; use App\Events\UserDeleted; use App\Events\UserDeleting; use Illuminate\Support\Facades\Log; class UserEventSubscriber { /** * 處理用戶刪除前事件 */ public function onUserDeleting($event) { Log::info('用戶即將刪除[' . $event->user->id . ']:' . $event->user->name); } /** * 處理用戶刪除後事件 */ public function onUserDeleted($event) { Log::info('用戶已經刪除[' . $event->user->id . ']:' . $event->user->name); } /** * 爲訂閱者註冊監聽器 * * @param Illuminate\Events\Dispatcher $events */ public function subscribe($events) { $events->listen( UserDeleting::class, UserEventSubscriber::class . '@onUserDeleting' ); $events->listen( UserDeleted::class, UserEventSubscriber::class . '@onUserDeleted' ); } }
EventServiceProvider
中註冊這個訂閱者// app/Providers/EventServiceProvider.php protected $subscribe = [ UserEventSubscriber::class ];
針對模型事件這種特殊的事件類型,Laravel 還爲咱們提供了觀察者類來處理模型事件的監聽。觀察者能夠看做是上述訂閱者處理模型事件的簡化版本,咱們不須要自定義事件類,不須要創建映射關係,只須要在觀察者類中將須要監聽的事件定義爲同名方法,並在相應方法中編寫業務處理代碼便可。當某個模型事件觸發時,Eloquent 底層會去該模型上註冊的觀察者類中經過反射查找是否認義了對應的方法,若是定義了則執行相應的邏輯,不然忽略。
下面以 saving
和 saved
事件爲例演示如何經過觀察者監聽模型事件。
User
模型的觀察者laravel5.7以上能夠使用如下命令進行建立觀察者,laravel5.7如下須要手動建立
php artisan make:observer UserObserver --model=Model/User
默認生成的 UserObserver
會爲 created
、 updated
、deleted
、restored
、forceDeleted
(強制刪除) 事件定義一個空方法:
<?php namespace App\Observers; use App\User; class UserObserver { /** * Handle the user "created" event. * * @param \App\User $user * @return void */ public function created(User $user) { // } /** * Handle the user "updated" event. * * @param \App\User $user * @return void */ public function updated(User $user) { // } /** * Handle the user "deleted" event. * * @param \App\User $user * @return void */ public function deleted(User $user) { // } /** * Handle the user "restored" event. * * @param \App\User $user * @return void */ public function restored(User $user) { // } /** * Handle the user "force deleted" event. * * @param \App\User $user * @return void */ public function forceDeleted(User $user) { // } }
能夠把前面定義的 retrived
、deleting
、deleted
事件監聽代碼遷移過來,也能夠將不需監聽的事件方法移除,這裏咱們將編寫保存模型時涉及的模型事件,包括 saving
、creating
、updating
、updated
、created
、saved
<?php namespace App\Observers; use App\Model\User; use Log; class UserObserver { public function saving(User $user) { Log::info('即將保存用戶到數據庫[' . $user->id . ']' . $user->name); } public function creating(User $user) { Log::info('即將插入用戶到數據庫[' . $user->id . ']' . $user->name); } public function updating(User $user) { Log::info('即將更新用戶到數據庫[' . $user->id . ']' . $user->name); } public function updated(User $user) { Log::info('已經更新用戶到數據庫[' . $user->id . ']' . $user->name); } public function created(User $user) { Log::info('已經插入用戶到數據庫[' . $user->id . ']' . $user->name); } public function saved(User $user) { Log::info('已經保存用戶到數據庫[' . $user->id . ']' . $user->name); } }
編寫好觀察者後,須要將其註冊到 User
模型上才能生效,咱們能夠在 EventServiceProvider
的 boot
方法中完成該工做:
public function boot() { parent::boot(); //註冊User模型的觀察者 User::observe(UserObserver::class); }
關於三種監聽 Eloquent 模型事件的方式,如何選擇,視狀況而定。若是隻是監聽一兩個模型事件,第一種方式比較合適;若是僅僅監聽系統支持的模型事件,而且要監聽多個模型的多個事件,觀察者是最佳選擇;若是還要在模型類上監聽更多系統模型事件以外的自定義事件,則使用訂閱者來監聽比較合適。