laravel进阶系列--通过事件和事件监听实现服务解耦
簡介
Laravel 事件提供了簡單的觀察著模式實現,允許你訂閱和監聽應用中的事件。事件類通常存放在 app/Events 目錄。
監聽器存放在 app/Listeners. 如果你在應用中沒有看到這些目錄,不要擔心,他們會在你使用Artisan命令生成事件和
監聽器的時候自動創建。
事件為應用功能模塊解耦提供了行之有效的解決方法,因為單個事件可以有多個監聽器而這些監聽器之間并不相互依賴。
例如,你可能想要在每次訂單發送時給用戶發送一個Slack通知,有了事件之后,你大可不必將訂單處理代碼和Slack
通知代碼耦合在一起,而只需要簡單觸發一個可以被監聽器接收并處理為Slack通知的 OrderShipped 事件即可。
注冊事件/監聽器
Laravel自動的 EventServerProvider 為時間監聽其注冊提供了方便之所。其中的listen屬性包含了事件(鍵)和對應
監聽器(值)數組.如果應用需要,你可以添加多個事件到給數組。下面讓我們添加一個 OrderShipped事件:
生成事件/監聽器類
當然,手動為每個事件和監聽器創建文件是很笨重的,取而代之的,我們只需簡單添加監聽器和事件到EventServiceProvider
然后運行 event:generate 命令。該命令將會生成羅列在EventServiceProider 中的所有事件和監聽器。當然,已存在
的事件和監聽器不會被重復創建:
php artisan event:generate
手動注冊事件
通常,我們需要通過 EventServiceProider 的$listen 數組注冊事件,此外,你還可以在EventServiceProvider 的
boot方法中手動注冊基于閉包的事件:
通配符事件監聽器
你甚至還可以使用通配符*來注冊監聽器,這樣就可以通過同一個監聽器捕獲多個事件。通配符監聽器接收整個
事件數據數組作為參數:
定義事件
事件類是一個處理與事件相關的簡單數據容器,例如,假設我們生成的 OrderShipped事件接收一個Eloquent ORM
對象:
<?php?
namespace App\Events;
use App\Order;
use Illuminate\Queue\SerializesModels;
class OrderShipped
{
use SerializesModels;
public $orders;
/*
創建一個新的實踐實例
@param Order $order
@return void
*/
public function __construct(Order $order)
{
$this->order = $order;
}
正如你所看到的,該事件類不包含任何特定邏輯,只是一個存放被購買的Order對象的容器,如果時間對象被序列化的話,
事件使用的SerializeModels trait 將會使用過PHP的serialize函數序列化所有Eloquent模型。
定義監聽器
接下來,讓我們看看實例事件的監聽器,事件監聽器在 handle方法中接收事件實例,event:generate 命令將會自動
在 handle方法中導入相應的事件類和類型提示事件。在handle方法內,你可以執行任何需要的邏輯以響應時間:
<?php
namespace App\Listeners;
use App\Events\OrderShipped;
class SendShipmentNotification
{
/*
創建事件監聽器
@return void
*/
public function __construct()
{
}
/*
處理事件
@param OrderShipped $event
@return void
*/
public funcion handle(OrderShipped $event)
{
//使用 $event->order 發訪問訂單...
}
}
?>
注: 事件監聽器還可以在構造器中類型提示任何需要的依賴,所有事件監聽器通過服務器解析,所以依賴會自動注入。
停止事件繼續往下傳播
有時候,你希望停止事件被傳播到其他監聽器,你可以通過從監聽器的handle方法中返回false來實現。
事件監聽器隊列
如果監聽器將要執行耗時任務比如發送郵件或者發送HTTP請求,那么將監聽器放到隊列是一個不錯的選擇。在隊列化
監聽器之前,確保已經配置好隊列并且在服務器或本地環境啟動一個隊列監聽器。
要指定某個監聽器需要放到隊列,只需要讓監聽器類實現 ShouldQueue 接口即可,通過Artisan命令event:generate
生成的監聽器類已經將這個接口導入當前命名空間,所以你可以直接拿來使用:
<?php?
namespace App\Listeners;
user App\Events\OrdersShipped;
use Illuminate\Contracts\Queue\ShowldQueue;
class SendShipmentNotification implements ShouldQueue
{
//
}
就是這么簡單!當這個監聽器被調用的時候,將會使用Laravel的隊列系統通過事件分發器自動推送到隊列。如果通過隊列
執行監聽器的時候沒有拋出任何異常,隊列任務會在執行完成后被自動刪除。
自定義隊列鏈接&隊列名稱
如果你想要自定義事件監聽器使用的隊列鏈接和隊列名稱,可以在監聽器類中定義$connection 和$queue屬性:
<?php
namespace App\Listeners;
use App\Events\OrdersShipped;
use Illuminate\Contracts\Queue\ShouldQueue
{
/*
任務將被推送到的鏈接名稱
*/
public $connection = 'sqs';
/*
任務將被推送到的鏈接名稱
@var string|null
*/
public $queue = 'listeners';
}
手動訪問隊列
如果你需要手動訪問底層隊列任務的delete和release方法,在生成的監聽器中,默認導入的Illuminate\Queue\InteractsWithQueue
trait 為這兩個方法提供了訪問權限:
<?php
namespace App\Listeners;
use App\Events\OrderShipped;
use Illuminate\Queue\InteractsWidthQueue;
use Illuminate\Contracts\Queue\ShowldQueue;
class SendShipmentNotification implements ShowldQueue
{
use InteractsWithQueue;
public function handle(OrderShipped $event)
{
if(true){
$this->release(30);
}
}
}
?
處理失敗任務
有時候隊列中的事件監聽器可能會執行失敗。如果隊列中的監聽器任務執行時超出了隊列進程定義的最大嘗試次數,監聽器上的
failed方法會被調用,failed方法接收事件實例和導致失敗的異常:
分發事件
要分發一個事件,可以傳遞事件實例到輔助函數event,這個輔助函數會分發事件到所有注冊的監聽器。由于輔助函數惡女他
全局有效,所以可以在應用的任何地方調用它:
注: 測試的時候,只需要斷言特定事件被分發,無需真正觸發監聽器,Laravel自帶的測試函數讓這一實現輕而易舉
事件訂閱者
編寫事件訂閱者
事件訂閱者是指那些在類本身中訂閱多個事件的類,通過事件訂閱者你可以在單個類中定義多個事件處理器。訂閱者需要定義一個
subscibe 方法,該方法中傳入一個事件分發器實例。你可以在給定的分發器匯總調用listen方法注冊事件監聽器
?
轉載于:https://www.cnblogs.com/simadongyang/p/8455411.html
總結
以上是生活随笔為你收集整理的laravel进阶系列--通过事件和事件监听实现服务解耦的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 路由器24小时开机不但不费钱-路由器24
- 下一篇: Bzoj5093: 图的价值