【laravel】Eloquent 模型事件和監聽方式

全部支持的模型事件

在 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 事件爲例演示如何經過觀察者監聽模型事件。

①經過 Artisan 命令建立針對 User 模型的觀察者

laravel5.7以上能夠使用如下命令進行建立觀察者,laravel5.7如下須要手動建立

php artisan make:observer UserObserver --model=Model/User

 默認生成的 UserObserver 會爲 created、 updateddeletedrestoredforceDeleted(強制刪除) 事件定義一個空方法:

<?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)
    {
        //
    }
}

能夠把前面定義的 retriveddeletingdeleted 事件監聽代碼遷移過來,也能夠將不需監聽的事件方法移除,這裏咱們將編寫保存模型時涉及的模型事件,包括 savingcreatingupdatingupdatedcreatedsaved

<?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 模型事件的方式,如何選擇,視狀況而定。若是隻是監聽一兩個模型事件,第一種方式比較合適;若是僅僅監聽系統支持的模型事件,而且要監聽多個模型的多個事件,觀察者是最佳選擇;若是還要在模型類上監聽更多系統模型事件以外的自定義事件,則使用訂閱者來監聽比較合適。

相關文章
相關標籤/搜索