Laravel イベントはシンプルなオブザーバー パターンの実装を提供し、アプリケーションでイベントをサブスクライブして監視できるようにします。通常、イベント クラスは app/Events ディレクトリに保存され、リスナーは app/Listeners に保存されます。
Laravel 独自の EventServiceProvider は、イベント登録に便利な場所を提供します。 listen 属性には、イベント (キー) の配列と対応するリスナー (値) が含まれます。アプリケーションで必要な場合は、この配列に複数のイベントを追加できます。たとえば、PodcastWasPurchased イベントを追加してみましょう。
/** * 事件监听器映射 * * @var array */protected $listen = [ 'App\Events\PodcastWasPurchased' => [ 'App\Listeners\EmailPurchaseConfirmation', ],];
もちろん、イベントとリスナーごとに手動でファイルを作成するのは面倒ですが、代わりに、次のように単純に追加できます。リスナーとイベントを EventServiceProvider に追加し、event:generate コマンドを使用します。このコマンドは、EventServiceProvider にリストされているすべてのイベントとリスナーを生成します。もちろん、既存のイベントとリスナーは作成されません。
php artisan event:generate
さらに、イベントを EventServiceProvider の $listen 配列に登録する必要があります。イベント ファサードまたは IlluminateContractsEventsDispatcher コントラクトの特定の実装クラスを使用して、イベントをイベント ディスパッチャーとして手動で登録することもできます。
/** * 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) { //});
イベント クラスは、イベントを処理する単純なデータ コンテナーです。生成した PodcastWasPurchased イベントが Eloquent ORM オブジェクトを受信すると仮定した場合、 などの関連データ:
<?phpnamespace App\Events;use App\Podcast;use App\Events\Event;use Illuminate\Queue\SerializesModels;class PodcastWasPurchased extends Event{ use SerializesModels; public $podcast; /** * 创建新的事件实例 * * @param Podcast $podcast * @return void */ public function __construct(Podcast $podcast) { $this->podcast = $podcast; }}
ご覧のとおり、このイベント クラスには特定のロジックが含まれておらず、単なるコンテナーです。イベント オブジェクトがシリアル化されている場合、イベントで使用される SerializesModelstrait は PHP のシリアライズ関数を使用してすべての Eloquent モデルをシリアル化します。
次に、イベント リスナーはハンドル メソッドのイベント インスタンスを受け取ります。 generate コマンドは、適切なイベント クラスとタイプ ヒント イベントをハンドル メソッドに自動的にインポートします。ハンドル メソッド内で、イベントに応答して必要なロジックを実行できます。
<?phpnamespace App\Listeners;use App\Events\PodcastWasPurchased;use Illuminate\Queue\InteractsWithQueue;use Illuminate\Contracts\Queue\ShouldQueue;class EmailPurchaseConfirmation{ /** * 创建事件监听器 * * @return void */ public function __construct() { // } /** * 处理事件 * * @param PodcastWasPurchased $event * @return void */ public function handle(PodcastWasPurchased $event) { // Access the podcast using $event->podcast... }}
イベント リスナーは、コンストラクターで必要な依存関係をタイプヒントで指定することもできます。すべてのイベント リスナーはサービス コンテナーを通じて解決されるため、依存関係は自動的に挿入されます。
use Illuminate\Contracts\Mail\Mailer;public function __construct(Mailer $mailer){ $this->mailer = $mailer;}
Stopイベントが伝播し続けるのを防ぎます
他のリスナーへのイベントの伝播を停止したい場合があります。リスナーのハンドル メソッドから false を返すことでこれを行うことができます。
イベント リスナーをキューに入れる必要がありますか?これほど簡単なことはありません。リスナー クラスに ShouldQueue インターフェイスを実装するだけです。Artisan コマンドのevent:generate によって生成されたリスナー クラスはすでに現在のネームスペースにインポートされているので、すぐに使用できます。 :
<?phpnamespace App\Listeners;use App\Events\PodcastWasPurchased;use Illuminate\Queue\InteractsWithQueue;use Illuminate\Contracts\Queue\ShouldQueue;class EmailPurchaseConfirmation implements ShouldQueue{ //}
それはとても簡単です。リスナーがイベントによって呼び出されるとき、Laravel のキュー システムを使用して、キュー ディスパッチャを通じて自動的にキューに入れられます。キューを介してリスナーを実行するときに例外がスローされなかった場合、キュー タスクは実行完了後に自動的に削除されます。
キューへの手動アクセス
基になるキュー タスクの削除メソッドと解放メソッドに手動でアクセスする必要がある場合、生成されたリスナーにデフォルトでインポートされる IlluminateQueueInteractsWithQueuetrait により、次の 2 つのメソッドへのアクセスが提供されます。
<?phpnamespace App\Listeners;use App\Events\PodcastWasPurchased;use Illuminate\Queue\InteractsWithQueue;use Illuminate\Contracts\Queue\ShouldQueue;class EmailPurchaseConfirmation implements ShouldQueue{ use InteractsWithQueue; public function handle(PodcastWasPurchased $event) { if (true) { $this->release(30); } }}
イベントをトリガーするには、Event ファサードを使用して、fire メソッドにイベント インスタンスを渡します。コントローラー:
<?phpnamespace App\Http\Controllers;use Event;use App\Podcast;use App\Events\PodcastWasPurchased;use App\Http\Controllers\Controller;class UserController extends Controller{ /** * 显示指定用户属性 * * @param int $userId * @param int $podcastId * @return Response */ public function purchasePodcast($userId, $podcastId) { $podcast = Podcast::findOrFail($podcastId); // Purchase podcast logic... Event::fire(new PodcastWasPurchased($podcast)); }}
さらに、グローバル補助関数イベントを使用してイベントをトリガーすることもできます:
event(new PodcastWasPurchased($podcast));
多くの最新の Web アプリケーションでは、リアルタイム更新のユーザー インターフェイスを実装するために Web ソケットが使用されています。サーバー上で一部のデータが更新されると、通常、WebSocket 接続を介してメッセージがクライアントに送信され、処理されます。
このようなアプリケーションの構築を支援するために、Laravel では WebSocket 接続を介してイベントを簡単にブロードキャストできるようにしています。 Laravel イベントをブロードキャストすると、サーバー側とクライアント側の JavaScript フレームワーク間で同じイベント名を共有できます。
すべてのイベント ブロードキャスト設定オプションは、config/broadcasting.php 設定ファイルに保存されます。 Laravel は、複数のブロードキャスト ドライバー (Pusher、Redis、ローカル開発およびデバッグ用のロギング ドライバー) をサポートしています。各ドライバーには構成例があります。
ブロードキャストの予備知識
イベント ブロードキャストには次の 2 つの依存関係が必要です:
キューの準備知識
在开始介绍广播事件之前,还需要配置并运行一个队列监听器。所有事件广播都通过队列任务来完成以便应用的响应时间不受影响。
要告诉 Laravel 给定事件应该被广播,需要在事件类上实现 Illuminate\Contracts\Broadcasting\ShouldBroadcast接口。 ShouldBroadcast接口要求你实现一个方法: broadcastOn。该方法应该返回事件广播“频道”名称数组:
<?phpnamespace App\Events;use App\User;use App\Events\Event;use Illuminate\Queue\SerializesModels;use Illuminate\Contracts\Broadcasting\ShouldBroadcast;class ServerCreated extends Event implements ShouldBroadcast{ use SerializesModels; public $user; /** * 创建新的事件实例 * * @return void */ public function __construct(User $user) { $this->user = $user; } /** * 获取事件广播频道 * * @return array */ public function broadcastOn() { return ['user.'.$this->user->id]; }}
然后,你只需要和正常一样触发该事件,事件被触发后,一个队列任务将通过指定广播驱动自动广播该事件。
如果某个事件被广播,其所有的 public属性都会按照事件负载自动序列化和广播,从而允许你从 JavaScript 中访问所有 public数据,因此,举个例子,如果你的事件有一个单独的包含 Eloquent 模型的 $user属性,广播负载定义如下:
{ "user": { "id": 1, "name": "Jonathan Banks" ... }}
然而,如果你希望对广播负载有更加细粒度的控制,可以添加 broadcastWith方法到事件,该方法应该返回你想要通过事件广播的数组数据:
/** * 获取广播数据 * * @return array */public function broadcastWith(){ return ['user' => $this->user->id];}
自定义事件名
默认情况下,广播事件名就是事件类名,因此,如果事件的类名是 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';}
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);});
事件订阅者是指那些在类本身中订阅到多个事件的类,从而允许你在单个类中定义一些事件处理器。订阅者应该定义一个 subscribe方法,该方法中传入一个事件分发器实例:
<?phpnamespace App\Listeners;class UserEventListener{ /** * 处理用户登录事件 */ public function onUserLogin($event) {} /** * 处理用户退出事件 */ public function onUserLogout($event) {} /** * 为订阅者注册监听器 * * @param Illuminate\Events\Dispatcher $events * @return array */ public function subscribe($events) { $events->listen( 'App\Events\UserLoggedIn', 'App\Listeners\UserEventListener@onUserLogin' ); $events->listen( 'App\Events\UserLoggedOut', 'App\Listeners\UserEventListener@onUserLogout' ); }}
注册一个事件订阅者
订阅者被定义后,可以通过事件分发器进行注册,你可以使用 EventServiceProvider上的 $subcribe属性来注册订阅者。例如,让我们添加 UserEventListener:
<?phpnamespace App\Providers;use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;class EventServiceProvider extends ServiceProvider{ /** * 事件监听器映射数组 * * @var array */ protected $listen = [ // ]; /** * 要注册的订阅者 * * @var array */ protected $subscribe = [ 'App\Listeners\UserEventListener', ];}