Laravel 的事件提供了一個簡單的觀察者實現,可以訂閱和監聽應用中發生的各類事件。事件類保存在 app/Events 目錄中,而這些事件的的監聽器則被保存在 app/Listeners 目錄下。這些目錄只有當你使用 Artisan 命令來生成事件和監聽器時纔會被自動建立。php
事件機制是一種很好的應用解耦方式,由於一個事件能夠擁有多個互不依賴的監聽器。例如,若是你但願每次訂單發貨時向用戶發送一個 Slack 通知。你能夠簡單地發起一個 OrderShipped 事件,讓監聽器接收以後轉化成一個 Slack 通知,這樣你就能夠不用把訂單的業務代碼跟 Slack 通知的代碼耦合在一塊兒了。laravel
好比經過 artisan 命令生成一個 UserLogin 事件:redis
php artisan make:event UserLogin
複製代碼
在 app/Events 中就會自動生成一個 UserLogin.php 文件,內容很少,以下:bash
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class UserLogin
{
use InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Get the channels the event should broadcast on.
*
* @return Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
}
複製代碼
一個事件能夠被一個或多個監聽器監聽,也就是觀察者模式,咱們能夠定義多個監聽器,當這個事件發生,執行一系列邏輯。app
在 EventServiceProvider 的 $listen 中能夠定義事件和監聽器,以下:異步
protected $listen = [
'App\Events\UserLogin' => [
'App\Listeners\DoSomething1',
'App\Listeners\Dosomething2',
],
];
複製代碼
而後執行 artisan 命令,就能夠自動在 app/Listeners 目錄生成監聽器。socket
php artisan event:generate
複製代碼
能夠看到 app/Listeners 目錄多了 DoSomething1.php 和 DoSomething2.php 兩個文件,咱們看看其中一個內容:ide
<?php
namespace App\Listeners;
use App\Events\UserLogin;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
class DoSomething1
{
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* @param UserLogin $event
* @return void
*/
public function handle(UserLogin $event)
{
info('do something1');
}
}
複製代碼
在兩個監聽器的 handle 方法中咱們打印一個日誌來測試一下,如代碼 handle 方法所示。測試
咱們在某個控制器的方法中來分發事件,也就是觸發事件,看監聽器是否正常工做。ui
就是一句話:
event(new UserLogin());
複製代碼
而後咱們請求這個控制器,觀察日誌,發現打印了日誌:
[2018-06-17 10:04:29] local.INFO: do something1 [2018-06-17 10:04:29] local.INFO: do something2
那麼這個事件-監聽機制就正常工做了。
若是某個監聽器須要執行的操做比較慢,能夠放到消息隊列進行異步處理。
好比把上面的 DoSomething1 改爲須要放入隊列的,只須要 implements ShoulQueue 接口。
class DoSomething1 implements ShouldQueue
複製代碼
也能夠指定隊列驅動,以下代碼。
/**
* 任務應該發送到的隊列的鏈接的名稱
*
* @var string|null
*/
public $connection = 'redis';
/**
* 任務應該發送到的隊列的名稱
*
* @var string|null
*/
public $queue = 'listeners';
複製代碼
咱們再次執行控制器方法。
日誌裏沒有打印 do something1,只有 do something2,可是在 redis 隊列裏發現了一個名爲 queues:default 的列表。
{"job":"Illuminate\\Events\\CallQueuedHandler@call","data":{"class":"App\\Listeners\\DoSomething1","method":"handle","data":"a:1:{i:0;O:20:\"App\\Events\\UserLogin\":1:{s:6:\"socket\";N;}}"},"id":"3D7VDUwueYGtUvsazicWsifwWQxnnLID","attempts":1}
複製代碼
這個時候須要使用 php artisan queue:work 執行隊列任務,纔是真正執行 DoSomething1 這個監聽器的 handle 方法。
(原文地址:https://blog.tanteng.me/2018/06/laravel-event/)