イントロダクションIntroduction
Laravelのイベント機能はオブザーバーのシンプルな実装を提供します。アプリケーションの中でイベントを発行し、購読するために使用します。イベントクラスは通常app/Events
ディレクトリへ保存され、リスナはapp/Listener
に設置します。Laravel's events provides a
simple observer implementation, allowing you to
subscribe and listen for events in your application.
Event classes are typically stored in the
app/Events
directory, while their
listeners are stored in
app/Listeners
.
イベント/リスナ登録Registering Events / Listeners
Laravelアプリケーションに含まれているEventServiceProvider
は、イベントリスナを全て登録するために便利な場所を提供しています。listen
プロパティは全イベント(キー)とリスナ(値)で構成されている配列です。もちろん、アプリケーションで必要とされているイベントをこの配列に好きなだけ追加できます。たとえばPodcastWasPurchased
イベントを追加してみましょう。The
EventServiceProvider
included with your
Laravel application provides a convenient place to
register all event listeners. The
listen
property contains an array of
all events (keys) and their listeners (values). Of
course, you may add as many events to this array as
your application requires. For example, let's add
our PodcastWasPurchased
event:
/**
* アプリケーションのイベントリスナをマップ
*
* @var array
*/
protected $listen = [
'App\Events\PodcastWasPurchased' => [
'App\Listeners\EmailPurchaseConfirmation',
],
];
イベントとリスナクラス生成Generating Event / Listener Classes
もちろん毎回ハンドラやリスナを作成するのは手間がかかります。代わりにハンドラとリスナをEventServiceProvider
に追加し、event:generate
コマンドを使いましょう。このコマンドはEventServiceProvider
にリストしてあるイベントやリスナを生成してくれます。既存のイベントとハンドラには当然変更を加えません。Of course, manually creating the
files for each event and listener is cumbersome.
Instead, simply add listeners and events to your
EventServiceProvider
and use the
event:generate
command. This command
will generate any events or listeners that are
listed in your EventServiceProvider
. Of
course, events and listeners that already exist will
be left untouched:
php artisan event:generate
イベントを自分で登録するRegistering Events Manually
通常、イベントはEventServiceProvider
の$listen
配列を使用し登録すべきです。しかし、Event
ファサードやIlluminate\Contracts\Events\Dispatcher
契約の実装を使用し、イベントディスパッチャーでイベントを自分で登録することもできます。Typically, events should be
registered via the EventServiceProvider
$listen
array; however, you may also
register events manually with the event dispatcher
using either the Event
facade or the
Illuminate\Contracts\Events\Dispatcher
contract implementation:
/**
* アプリケーションのその他のイベントを登録
*
* @param \Illuminate\Contracts\Events\Dispatcher $events
* @return void
*/
public function boot(DispatcherContract $events)
{
parent::boot($events);
$events->listen('event.name', function ($foo, $bar) {
//
});
}
ワイルドカードイベントリスナWildcard Event Listeners
*
をワイルドカードとしてリスナを登録することができ、同じリスナで複数のイベントを補足することが可能です。ワイルドカードリスナは一つの引数により、イベントデータ全体の配列を受け取ります。You may even register listeners
using the *
as a wildcard, allowing you
to catch multiple events on the same listener.
Wildcard listeners receive the entire event data
array as a single argument:
$events->listen('event.*', function (array $data) {
//
});
イベント定義Defining Events
イベントクラスはシンプルなデータコンテナで、イベントに関する情報を保持します。たとえば生成したPodcastWasPurchased
イベントがEloquent
ORMオブジェクトを受け取るとしましょう。An
event class is simply a data container which holds
the information related to the event. For example,
let's assume our generated
PodcastWasPurchased
event receives an
Eloquent ORM[/docs/{{version}}/eloquent]
object:
<?php
namespace 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;
}
}
ご覧の通り、このクラスはロジックを含みません。購入されたPodcast
オブジェクトのための、単なるコンテナに過ぎません。イベントオブジェクトがPHPのserialize
関数でシリアライズされる場合でも、EloquentモデルはSerializesModels
トレイトが優雅にシリアライズします。As you can see, this event class
contains no logic. It is simply a container for the
Podcast
object that was purchased. The
SerializesModels
trait used by the
event will gracefully serialize any Eloquent models
if the event object is serialized using PHP's
serialize
function.
リスナの定義Defining Listeners
次にサンプルイベントのリスナを取り上げましょう。イベントリスナはイベントインスタンスをhandle
メソッドで受け取ります。event:generate
コマンドは自動的に対応するイベントクラスをインポートし、handle
メソッドのイベントのタイプヒントを行います。そのイベントに対応するために必要なロジックを実行してください。Next, let's take a look at the
listener for our example event. Event listeners
receive the event instance in their
handle
method. The
event:generate
command will
automatically import the proper event class and
type-hint the event on the handle
method. Within the handle
method, you
may perform any logic necessary to respond to the
event.
<?php
namespace App\Listeners;
use App\Events\PodcastWasPurchased;
class EmailPurchaseConfirmation
{
/**
* イベントリスナ生成
*
* @return void
*/
public function __construct()
{
//
}
/**
* イベントの処理
*
* @param PodcastWasPurchased $event
* @return void
*/
public function handle(PodcastWasPurchased $event)
{
// $event->podcastにより、ポッドキャストへアクセス
}
}
イベントリスナは必要な依存をコンストラクターのタイプヒントで指定できます。イベントリスナは全てLaravelのサービスコンテナで依存解決されるので、依存は自動的に注入されます。Your event listeners may also type-hint any dependencies they need on their constructors. All event listeners are resolved via the Laravel service container[/docs/{{version}}/container], so dependencies will be injected automatically:
use Illuminate\Contracts\Mail\Mailer;
public function __construct(Mailer $mailer)
{
$this->mailer = $mailer;
}
イベントの伝播の停止Stopping The Propagation Of An Event
場合によりイベントが他のリスナへ伝播されるのを止めたいこともあります。その場合はhandle
メソッドからfalse
を返してください。Sometimes, you may wish to stop
the propagation of an event to other listeners. You
may do so by returning false
from your
listener's handle
method.
イベントリスナのキュー投入Queued Event Listeners
イベントリスナをキューに投入する必要があるのですか?
これ以上ないくらい簡単です。リスナクラスにShouldQueue
インターフェイスを追加するだけです。リスナがevent:generate
Artisanコマンドにより生成されている場合は、現在の名前空間下にこのインターフェイスがインポートされていますので、すぐに使用できます。Need to
queue[/docs/{{version}}/queues] an event
listener? It couldn't be any easier. Simply add the
ShouldQueue
interface to the listener
class. Listeners generated by the
event:generate
Artisan command already
have this interface imported into the current
namespace, so you can use it immediately:
<?php
namespace App\Listeners;
use App\Events\PodcastWasPurchased;
use Illuminate\Contracts\Queue\ShouldQueue;
class EmailPurchaseConfirmation implements ShouldQueue
{
//
}
これだけです!これでこのリスナがイベントのために呼び出されると、Laravelのキューシステムを使い、イベントデスパッチャーにより自動的にキューへ投入されます。キューにより実行されるリスナから例外が投げられなければ、そのキュージョブは処理が済んだら自動的に削除されます。That's it! Now, when this listener is called for an event, it will be queued automatically by the event dispatcher using Laravel's queue system[/docs/{{version}}/queues]. If no exceptions are thrown when the listener is executed by the queue, the queued job will automatically be deleted after it has processed.
キューへのアクセスManually Accessing The Queue
裏で動作しているキュージョブのdelete
やrelease
メソッドを直接呼び出したければ可能です。生成されたリスナではデフォルトでインポートされているIlluminate\Queue\InteractsWithQueue
トレイトを呼び出してください。両メソッドへのアクセスを提供します。If you need to access the
underlying queue job's delete
and
release
methods manually, you may do
so. The
Illuminate\Queue\InteractsWithQueue
trait, which is imported by default on generated
listeners, gives you access to these
methods:
<?php
namespace 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);
}
}
}
イベント発行Firing Events
イベントを発行するにはEvent
ファサードを使用し、fire
メソッドにイベントのインスタンスを渡してください。fire
メソッドはそのイベントを登録されているリスナ全部へディスパッチします。To fire an event, you may use the
Event
facade[/docs/{{version}}/facades], passing an
instance of the event to the fire
method. The fire
method will dispatch
the event to all of its registered
listeners:
<?php
namespace 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);
// ポッドキャスト購入ロジック…
Event::fire(new PodcastWasPurchased($podcast));
}
}
もしくは、グローバルなevent
ヘルパ関数でイベントを発行します。Alternatively, you may use the
global event
helper function to fire
events:
event(new PodcastWasPurchased($podcast));
ブロードキャストイベントBroadcasting Events
多くの近代的なアプリケーションでは、リアルタイムでライブ更新されるユーザインターフェイスを実装するために、Webソケットを利用しています。サーバーであるデータが更新されたら、処理するクライアントへWebソケット接続を通じて送られます。In many modern web applications, web sockets are used to implement real-time, live-updating user interfaces. When some data is updated on the server, a message is typically sent over a websocket connection to be handled by the client.
こうしたタイプのアプリケーション構築を援助するため、LaravelはイベントをWebソケット接続を通じて簡単に「ブロードキャスト」できます。Laravelのイベントをブロードキャストすることで、サーバーサイドのコードとクライアントサイドのJavaScriptで同じ名前のイベントを共有できるようになります。To assist you in building these types of applications, Laravel makes it easy to "broadcast" your events over a websocket connection. Broadcasting your Laravel events allows you to share the same event names between your server-side code and your client-side JavaScript framework.
設定Configuration
イベントブロードキャストの設定オプションはconfig/broadcasting.php
設定ファイルの中にあります。Laravelはいくつかのドライバを用意しており、PusherやRedis、それにローカルの開発とデバッグのためのlog
ドライバがあります。All of the event broadcasting
configuration options are stored in the
config/broadcasting.php
configuration
file. Laravel supports several broadcast drivers out
of the box: Pusher[https://pusher.com],
Redis[/docs/{{version}}/redis], and a
log
driver for local development and
debugging. A configuration example is included for
each of these drivers.
ブロードキャスト事前要件Broadcast Prerequisites
以下の依存パッケージがイベントのブロードキャストに必要です。The following dependencies are needed for event broadcasting:
- Pusher:
pusher/pusher-php-server ~2.0
Pusher:pusher/pusher-php-server ~2.0
- Redis:
predis/predis ~1.0
Redis:predis/predis ~1.0
動作要件:キューQueue Prerequisites
イベントをブロードキャストする前に、キューリスナを設定し動かしておく必要があります。全てのイベントブロードキャストはキュー投入されるジョブとして動きますので、アプリケーションの反応時間にシリアスな影響を与えません。Before broadcasting events, you will also need to configure and run a queue listener[/docs/{{version}}/queues]. All event broadcasting is done via queued jobs so that the response time of your application is not seriously affected.
ブロードキャストイベント作成Marking Events For Broadcast
Laravelにイベントがブロードキャストされることを知らせるためにIlluminate\Contracts\Broadcasting\ShouldBroadcast
インターフェイスを実装してください。ShouldBroadcast
インターフェイスはbroadcastOn
メソッドの実装ひとつだけを求めます。broadcastOn
メソッドはブロードキャストされる「チャンネル」名の配列を返す必要があります。To inform Laravel that a
given event should be broadcast, implement
the
Illuminate\Contracts\Broadcasting\ShouldBroadcast
interface on the event class. The
ShouldBroadcast
interface
requires you to implement a single method:
broadcastOn
. The
broadcastOn
method should
return an array of "channel" names
that the event should be broadcast
on:
<?php
namespace 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];
}
}
それから、通常通りにイベントを発行するだけです。イベントが発行されるとキュージョブで指定されたブロードキャストドライバにより自動的にブロードキャストされます。Then, you only need to fire the event[#firing-events] as you normally would. Once the event has been fired, a queued job[/docs/{{version}}/queues] will automatically broadcast the event over your specified broadcast driver.
ブロードキャストデータBroadcast Data
イベントをブロードキャストする時、全public
プロパティーは自動的にシリアライズされ、イベントの本体(ペイロード)としてブロードキャストされます。それによりJavaScriptアプリケーションでパブリックデータへアクセスできるようになります。たとえばイベントにEloquentモデルのpublicの$user
プロパティがあったとすると、ブロードキャストの本体は次のようになります。When an event is
broadcast, all of its public
properties are automatically serialized and
broadcast as the event's payload, allowing
you to access any of its public data from
your JavaScript application. So, for
example, if your event has a single public
$user
property that contains an
Eloquent model, the broadcast payload would
be:
{
"user": {
"id": 1,
"name": "Jonathan Banks"
...
}
}
しかしブロードキャストされる本体をより良く調整、コントロールしたければ、broadcastWith
メソッドをイベントに追加してください。このメソッドは、そのイベントでブロードキャストしたいデータの配列を返す必要があります。However, if you wish to
have even more fine-grained control over
your broadcast payload, you may add a
broadcastWith
method to your
event. This method should return the array
of data that you wish to broadcast with the
event:
/**
* ブロードキャストするデータ取得
*
* @return array
*/
public function broadcastWith()
{
return ['user' => $this->user->id];
}
イベントブロードキャストカスタマイズEvent Broadcasting Customizations
イベント名のカスタマイズCustomizing The Event Name
ブロードキャストイベント名はデフォルトで、そのイベントの完全なクラス名となっています。ですから、イベントのクラス名がApp\Events\ServerCreated
ならば、ブロードキャストイベントはApp\Events\ServerCreated
になります。イベントクラスのbroadcastAs
メソッドで定義すれば、このブロードキャストイベント名をカスタマイズ可能です。By default, the broadcast
event name will be the fully qualified class
name of the event. So, if the event's class
name is
App\Events\ServerCreated
, the
broadcast event would be
App\Events\ServerCreated
. You
can customize this broadcast event name
using by defining a broadcastAs
method on your event class:
/**
* ブロードキャストイベント名の取得
*
* @return string
*/
public function broadcastAs()
{
return 'app.server-created';
}
キューのカスタマイズCustomizing The Queue
デフォルトで、ブロードキャストされるイベントは、queue.php
設定ファイルのデフォルトキュー接続のデフォルトキューへ投入されます。イベントクラスへonQueue
メソッドを追加すれば、イベントブロードキャスで使用されるキューをカスタマイズできます。このメソッドは、使用するキュー名を返します。By default, each event to
be broadcast is placed on the default queue
for the default queue connection in your
queue.php
configuration file.
You may customize the queue used by the
event broadcaster by adding an
onQueue
method to your event
class. This method should return the name of
the queue you wish to use:
/**
* イベントが投入されるキュー名
*
* @return string
*/
public function onQueue()
{
return 'your-queue-name';
}
イベントブロードキャストの利用Consuming Event Broadcasts
PusherPusher
PusherのJavaScript
SDKを使い、Pusherドライバでイベントブロードキャストを便利に使いたいと思うでしょう。たとえば前例のApp\Events\ServerCreated
イベントを使ってみましょう。You may conveniently
consume events broadcast using the
Pusher[https://pusher.com] driver
using Pusher's JavaScript SDK. For example,
let's consume the
App\Events\ServerCreated
event
from our previous examples:
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);
});
RedisRedis
Redisブロードキャストを使用する場合、メッセージを受け取るために自分でRedisのpub/subコンシューマーを書く必要があり、自分で選んだWebソケットのテクノロジーを使いブロードキャストしなくてはなりません。たとえばNodeで書かれ人気のあるSocket.ioライブラリーを使うことを選択できます。If you are using the Redis broadcaster, you will need to write your own Redis pub/sub consumer to receive the messages and broadcast them using the websocket technology of your choice. For example, you may choose to use the popular Socket.io[http://socket.io] library which is written in Node.
socket.io
とioredis
Nodeライブラリーを使い、Laravelアプリケーションからブロードキャストされた全イベントを発行するイベントブロードキャスターを簡単に書けます。Using the
socket.io
and
ioredis
Node libraries, you can
quickly write an event broadcaster to
publish all events that are broadcast by
your Laravel application:
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);
});
イベント購読Event Subscribers
イベント購読クラスは一つのクラスで多くのイベントを購読するためのものです。購読クラスはイベントデスパッチャーインスタンスが渡されるsubscribe
メソッドを実装しなくてはなりませんEvent subscribers are
classes that may subscribe to multiple
events from within the class itself,
allowing you to define several event
handlers within a single class. Subscribers
should define a subscribe
method, which will be passed an event
dispatcher instance:
<?php
namespace App\Listeners;
class UserEventListener
{
/**
* ユーザーログインイベントの処理
*/
public function onUserLogin($event) {}
/**
* ユーザーログアウトイベントの処理
*/
public function onUserLogout($event) {}
/**
* イベント購読リスナの登録
*
* @param Illuminate\Events\Dispatcher $events
*/
public function subscribe($events)
{
$events->listen(
'App\Events\UserLoggedIn',
'App\Listeners\UserEventListener@onUserLogin'
);
$events->listen(
'App\Events\UserLoggedOut',
'App\Listeners\UserEventListener@onUserLogout'
);
}
}
イベント購読クラスの登録Registering An Event Subscriber
購読クラスを定義したらイベントディスパッチャーに登録します。EventServiceProvider
の$subscribe
プロパティを使い、後続クラスを登録します。たとえばUserEventListener
を追加してみましょう。Once the subscriber has
been defined, it may be registered with the
event dispatcher. You may register
subscribers using the
$subscribe
property on the
EventServiceProvider
. For
example, let's add the
UserEventListener
.
<?php
namespace 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',
];
}