1. 程式人生 > 其它 >[譯]Laravel 5.0 之事件及處理程式

[譯]Laravel 5.0 之事件及處理程式

本文譯自 Matt Stauffer系列文章.


提示:如果你還沒有看過 Laravel 5.0 之命令及處理程式 這篇文章,建議先看一下。它包括了本文所需的背景知識。

藉助 Laravel 5 的命令(及命令處理程式),你可以通過封裝的方式非常簡單、直接地向系統發出命令。DoThis.HandleACommandThatIsTellingMeToDoThis, 它是命令式的,告訴系統要做什麼事。

但有時候,不管是在命令結果中,還是在其它的上下文中,我們需要發出更抽象的通知。比如在 Laravel 4 中,可以直接以事件名稱的字串來觸發事件(而不是像上面那樣通過物件和方法):

$response = Event::fire('auth.login', array($user));

這行程式碼向整個應用發出一條通知:“有人登陸了,這是使用者資訊”。它是知會式的,只是知會事件發生比提供相關資訊。如果你熟悉“釋出/訂閱”概念的話,這就是“事件”機制要處理的。

在 Laravel 5 中,事件系統已經得到了升級,看上去與上一篇文章中介紹過的命令系統有幾分相似。在升級後的事件系統中,不是基於字串來標識事件(比如 "auth.login"),而是建立一個 PHP 物件,併發布它。

示例

接下來,直接以例子來做說明:

生成事件

$ php artisan make:event ThingWasDone

... 這行命令會生成下面的程式碼:

namespace SaveMyProposalsEvents;

use SaveMyProposalsEventsEvent;

use IlluminateQueueSerializesModels;

class ThingWasDone extends Event {

    use SerializesModels;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

}

你可以給建構函式新增引數並把引數值繫結到類的屬性值,通過這樣的方式為這個類提供額外的資料。

生成事件處理程式

執行命令:

$ php artisan handler:event SendMailInSomeParticularContext --event="ThingWasDone"

這行程式碼會生成下面的程式碼:

namespace SaveMyProposalsHandlersEvents;

use SaveMyProposalsEventsThingWasDone;

use IlluminateQueueInteractsWithQueue;
use IlluminateContractsQueueShouldBeQueued;

class SendMailInSomeParticularContext {

    /**
     * Create the event handler.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Handle the event.
     *
     * @param  ThingWasDone  $event
     * @return void
     */
    public function handle(ThingWasDone $event)
    {
        //
    }

}

需要注意的一點是,生成的程式碼中,已經為 handle 方法指定了一個帶有型別約束的 ThingWasDone $event 引數。不管是建構函式還是 event 方法,你都可以藉助依賴注入來提供任何你需要的工具或物件。

繫結事件

在上一個步驟中我們建立了一個事件及其處理程式,但僅僅是建立,並沒有通知事件匯流排(bus)我們剛才建立的事件和處理程式是配對的。所以接下來還需要在 appProvidersEventServiceProvider 中繫結它們的監聽關係,可以在 $listen 屬性中做這件事:

// appProvidersEventServiceProvider
    $listen = [
        ThingWasDone::class => [
            SendMailInSomeParticularContext::class,
            SaveSomeRecordInSomeOtherContext::class,
            DoSomethingElseInResponseToThingBeingDone::class
        ]
    ];

如你所見,通過 ::class 得到一個代表事件類名的字串作為 key,然後在值陣列中新增監聽器(也是通過 ::class)。

“預備...瞄準...開火(::fire)”

好了,一切準備就緒,接下來就是觸發該事件了。要注意的是這裡只有簡單的 PHP 類,所以你可以手動例項化事件,例項化事件對應的處理程式,然後把事件傳遞給處理程式。但那當然不是 Laravel 的思路, Laravel 提供了事件匯流排讓以上這一系列的工作更簡單,更具有一致性和全域性性:

Event::fire(new ThingWasDone($param1, $param2));

就這麼簡單!

ShouldBeQueued

與命令系統的機制一樣,你可以讓你的事件實現 IlluminateContractsQueueShouldBeQueued 介面,從而使事件處理程式被加入到佇列中非同步執行;也可以給你的事件處理程式加上 IlluminateQueueInteractsWithQueue 的 trait,使事件處理程式的 handle 方法變得容易從外部訪問,從而使事件處理程式可以和事件佇列進行互動。比如在佇列中刪除當前的任務。

SerializesModels trait

還是與命令一樣的,如果你需要在事件中用到某個 Eloquent 模型,你可以在事件類的程式碼頂部包含 SerializesModels 這個 trait。在本文寫作時,生成的時間程式碼實際上已經預設包含了這部分。

寫在最後

就這麼多了。只要你理解了 Laravel 5 的命令和處理程式,掌握事件處理機制就是一件非常容易的事了。觸發系統向整個應用發出通知說某個事件發生了,而不是要求系統執行某些操作。但本質上它們都是封裝的資訊和目的。它們可以互相配合使用,結果會更棒!