[譯]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 的命令和處理程式,掌握事件處理機制就是一件非常容易的事了。觸發系統向整個應用發出通知說某個事件發生了,而不是要求系統執行某些操作。但本質上它們都是封裝的資訊和目的。它們可以互相配合使用,結果會更棒!