1、簡介
Laravel事件提供了簡單的觀察者模式實現,允許你訂閱和監聽應用中的事件。事件類別通常存放在 app/Events目錄,監聽器存放在 app/Listeners。
2、註冊事件/監聽器
Laravel 內建的 EventServiceProvider為事件註冊提供了方便之所。其中的 listen屬性包含了事件(鍵)和對應監聽器(值)數組。如果應用需要,你可以添加多個事件到該數組。例如,讓我們添加 PodcastWasPurchased事件:
/** * 事件監聽器映射 * * @var array */protected $listen = [ 'App\Events\PodcastWasPurchased' => [ 'App\Listeners\EmailPurchaseConfirmation', ],];
2.1 建置事件/監聽器類
當然,手動為每個事件和監聽器建立檔案是很笨重的,取而代之地,我們可見簡單添加監聽器和事件到 EventServiceProvider然後使用 event:generate命令。該命令將會產生羅列在 EventServiceProvider中的所有事件和監聽器。當然,已存在的事件和監聽器不會被建立:
php artisan event:generate
2.2 手動註冊事件
一般我們需要將事件註冊到 EventServiceProvider的 $listen數組,此外,我們還可以使用 Event門面或者 Illuminate\Contracts\Events\Dispatcher契約的具體實作類別作為事件分發器手動註冊事件:
/** * Register any other events for your application. * * @param \Illuminate\Contracts\Events\Dispatcher $events * @return void */public function boot(DispatcherContract $events){ parent::boot($events); $events->listen('event.name', function ($foo, $bar) { // });}
使用萬用字元作為事件監聽器
你還可以使用萬用字元*來註冊監聽器,從而允許你通過同一個監聽器捕獲多個事件。萬用字元監聽器接收整個事件數目據數組作為參數:
$events->listen('event.*', function (array $data) { //});
3、定義事件
事件類別是一個處理與事件相關的簡單資料容器,例如,假設我們產生的 PodcastWasPurchased事件接收一個Eloquent ORM對象:
podcast = $podcast; }}
正如你所看到的,該事件類別不包含任何特定邏輯,只是一個存放被購買的 Podcast對象的容器,如果事件對象被序列化的話,事件使用的 SerializesModelstrait 將會使用 PHP 的 serialize函數序列化所有 Eloquent 模型。
4、定義監聽器
接下來,讓我們看看我們的樣本事件的監聽器,事件監聽器在 handle方法中接收事件執行個體, event:generate命令將會自動在 handle方法中匯入合適的事件類別和類型提示事件。在 handle方法內,你可以執行任何需要的邏輯以響應事件。
podcast... }}
你的事件監聽器還可以在構造器中類型提示任何需要的依賴,所有事件監聽器通過服務容器解析,所以依賴會自動注入:
use Illuminate\Contracts\Mail\Mailer;public function __construct(Mailer $mailer){ $this->mailer = $mailer;}
停止事件繼續往下傳播
有時候,你希望停止事件被傳播到其它監聽器,你可以通過從監聽器的 handle方法中返回 false來實現。
事件監聽器隊列
需要將事件監聽器放到隊列?沒有比這更簡單的了,只需要讓監聽器類實現 ShouldQueue介面即可,通過 Artisan 命令 event:generate產生的監聽器類已經將介面匯入當前命名空間,所有你可以立即拿來使用:
就是這麼簡單,當監聽器被事件調用,將會使用 Laravel 的隊列系統通過隊列分發器自動隊列化。如果通過隊列執行監聽器的時候沒有拋出任何異常,隊列任務在執行完成後被自動刪除。
手動訪問隊列
如果你需要手動訪問底層隊列任務的 delete和 release方法,在產生的監聽器中預設匯入的 Illuminate\Queue\InteractsWithQueuetrait 提供了訪問這兩個方法的許可權:
release(30); } }}
5、觸發事件
要觸發一個事件,可以使用 Event門面,傳遞一個事件執行個體到 fire方法, fire方法會分發事件到所有監聽器:
此外,你還可以使用全域的輔助函數 event來觸發事件:
event(new PodcastWasPurchased($podcast));
6、 廣播事件
在很多現代 Web 應用程式中,Web 通訊端被用於實現即時更新的使用者介面。當一些資料在伺服器上被更新,通常一條訊息通過 websocket 串連被發送給用戶端處理。
為協助你構建這樣的應用,Laravel 讓通過 websocket 串連廣播事件變得簡單。廣播 Laravel 事件允許你在服務端和用戶端 JavaScript 架構之間共用同一事件名。
6.1 配置
所有的事件廣播配置選項都存放在 config/broadcasting.php設定檔中。Laravel 支援多種廣播驅動: Pusher、Redis以及一個服務於本地開發和調試的日誌驅動。每一個驅動都有一個配置樣本。
廣播預備知識
事件廣播需要以下兩個依賴:
- Pusher: pusher/pusher-php-server ~2.0
- Redis: predis/predis ~1.0
隊列預備知識
在開始介紹廣播事件之前,還需要配置並運行一個隊列監聽器。所有事件廣播都通過隊列任務來完成以便應用的回應時間不受影響。
6.2 將事件標記為廣播
要告訴 Laravel 給定事件應該被廣播,需要在事件類別上實現 Illuminate\Contracts\Broadcasting\ShouldBroadcast介面。 ShouldBroadcast介面要求你實現一個方法: broadcastOn。該方法應該返回事件廣播“頻道”名稱數組:
user = $user; } /** * 擷取事件廣播頻道 * * @return array */ public function broadcastOn() { return ['user.'.$this->user->id]; }} 然後,你只需要和正常一樣觸發該事件,事件被觸發後,一個隊列任務將通過指定廣播驅動自動廣播該事件。
6.3 廣播資料
如果某個事件被廣播,其所有的 public屬性都會按照事件裝載自動序列化和廣播,從而允許你從 JavaScript 中訪問所有 public資料,因此,舉個例子,如果你的事件有一個單獨的包含 Eloquent 模型的 $user屬性,廣播負載定義如下:
{ "user": { "id": 1, "name": "Jonathan Banks" ... }} 然而,如果你希望對廣播負載有更加細粒度的控制,可以添加 broadcastWith方法到事件,該方法應該返回你想要通過事件廣播的數組資料:
/** * 擷取廣播資料 * * @return array */public function broadcastWith(){ return ['user' => $this->user->id];} 6.4 自訂事件廣播
自訂事件名
預設情況下,廣播事件名就是事件類別名,因此,如果事件的類名是 App\Events\ServerCreated,對應的廣播事件名就是 App\Events\ServerCreated,你可以通過事件類別上的 broadcastAs方法自訂廣播事件名:
/** * 擷取廣播事件名稱 * * @return string */public function broadcastAs(){ return 'app.server-created';} 自訂隊列
預設情況下,每個被廣播的事件都位於設定檔 queue.php中定義的預設隊列串連中的預設隊列中,你可以通過事件類別的 onQueue方法自訂廣播事件的隊列名稱。該方法會返回你期望使用的隊列名:
/** * 設定事件所在隊列的名稱 * * @return string */public function onQueue(){ return 'your-queue-name';} 6.5 消費事件廣播
Pusher
你可以通過 Pusher 的 JavaScript SDK 方便地使用 Pusher驅動消費事件廣播。例如,讓我們從之前的例子中消費 App\Events\ServerCreated事件:
this.pusher = new Pusher('pusher-key');this.pusherChannel = this.pusher.subscribe('user.' + USER_ID);this.pusherChannel.bind('App\\Events\\ServerCreated', function(message) { console.log(message.user);}); Redis
如果你在使用 Redis 廣播,你將需要編寫自己的 Redis pub/sub 消費者來接收訊息並使用自己選擇的 websocket 技術將其進行廣播。例如,你可以選擇使用 Node 編寫的流行的 Socket.io庫。
使用 Node 庫 socket.io和 ioredis,你可以快速編寫事件廣播發布所有廣播事件:
var app = require('http').createServer(handler);var io = require('socket.io')(app);var Redis = require('ioredis');var redis = new Redis();app.listen(6001, function() { console.log('Server is running!');});function handler(req, res) { res.writeHead(200); res.end('');}io.on('connection', function(socket) { //});redis.psubscribe('*', function(err, count) { //});redis.on('pmessage', function(subscribed, channel, message) { message = JSON.parse(message); io.emit(channel + ':' + message.event, message.data);}); 7、事件訂閱者
事件訂閱者是指那些在類本身中訂閱到多個事件的類,從而允許你在單個類中定義一些事件處理器。訂閱者應該定義一個 subscribe方法,該方法中傳入一個事件分發器執行個體:
listen( 'App\Events\UserLoggedIn', 'App\Listeners\UserEventListener@onUserLogin' ); $events->listen( 'App\Events\UserLoggedOut', 'App\Listeners\UserEventListener@onUserLogout' ); }}
註冊一個事件訂閱者
訂閱者被定義後,可以通過事件分發器進行註冊,你可以使用 EventServiceProvider上的 $subcribe屬性來註冊訂閱者。例如,讓我們添加 UserEventListener: