1. 程式人生 > >【laravel】Eloquent 模型事件和監聽方式

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

pat pda 需要 er模型 The 編寫 三種 min sub

所有支持的模型事件

在 Eloquent 模型類上進行查詢、插入、更新、刪除操作時,會觸發相應的模型事件,不管你有沒有監聽它們。這些事件包括:

retrieved 獲取到模型實例後觸發
creating 插入到數據庫前觸發
created 插入到數據庫後觸發
updating 更新到數據庫前觸發
updated 更新到數據庫後觸發
saving 保存到數據庫前觸發(插入/更新之前,無論插入還是更新都會觸發)
saved 保存到數據庫後觸發(插入/更新之後,無論插入還是更新都會觸發)
deleting
從數據庫刪除記錄前觸發
deleted 從數據庫刪除記錄後觸發
restoring 恢復軟刪除記錄前觸發
restored 恢復軟刪除記錄後觸發

註:批量更新時不會觸發相應事件,因為是直接走查詢構建器完成的,繞過了模型方法。

通過監聽這些事件,我們可以在 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 門面記錄日誌信息。

通過訂閱者監聽模型事件

①先創建對應的事件類

以刪除模型為例進行演示,分別定義一個刪除前事件類刪除後事件類。我們通過 Artisan 命令來完成事件類初始化:

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 屬性來完成:

//建立模型事件與自定義事件類的映射
protected $dispatchesEvents = [
    ‘deleting‘ => UserDeleting::class,
    ‘deleted‘ => UserDeleted::class
];

這樣,當我們觸發 deleting deleted 事件時,底層會將其轉化為觸發 UserDeleting UserDeleted 事件。

③創建訂閱者監聽事件類

我們還要監聽上述自定義的事件類,我們可以通過在 EventServiceProvider listen 屬性中為每個事件綁定對應的監聽器類,也可以通過為某個模型類創建一個事件訂閱者類來統一處理該模型中的所有事件。在 app/Listeners 目錄下創建一個 UserEventSubscriber.php 文件作為訂閱者類,編寫代碼如下

<?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 模型的觀察者

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

默認生成的 UserObserver 會為 createdupdateddeletedrestoredforceDeleted(強制刪除) 事件定義一個空方法:

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

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