イントロダクション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 special 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;
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)
{
// $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\Queue\InteractsWithQueue;
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.
ブロードキャストイベント名のオーバーライドOverriding Broadcast Event Name
ブロードキャストイベント名は、デフォルトでそのイベントの完全な名前空間名になります。上の例のクラスでは、ブロードキャストイベントは、App\Events\ServerCreated
になります。broadcastAs
メソッドにより、このブロードキャストイベント名を好きなようにカスタマイズできます。By default, the broadcast
event name will be the fully qualified class
name of the event. Using the example class
above, the broadcast event would be
App\Events\ServerCreated
. You
can customize this broadcast event name to
whatever you want using the
broadcastAs
method:
/**
* ブロードキャストイベント名の取得
*
* @return string
*/
public function broadcastAs()
{
return 'app.server-created';
}
ブロードキャストデータ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];
}
イベントブロードキャストの利用Consuming Event Broadcasts
PusherPusher
PusherのJacaScript
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',
];
}
フレームワークのイベントFramework Events
Laravelはフレームワークが実行するアクションに対して発行する、様々な「コア」イベントを提供しています。皆さんが独自に用意するカスタムイベントと同じ方法で、これらのコアイベントも購入できます。Laravel provides a variety of "core" events for actions performed by the framework. You can subscribe to them in the same way that you subscribe to your own custom events:
イベントEvent | パラメータParameter(s) |
---|---|
artisan.startartisan.start | $application$application |
auth.attemptauth.attempt | $credentials, $remember, $login$credentials, $remember, $login |
auth.loginauth.login | $user, $remember$user, $remember |
auth.logoutauth.logout | $user$user |
cache.missedcache.missed | $key$key |
cache.hitcache.hit | $key, $value$key, $value |
cache.writecache.write | $key, $value, $minutes$key, $value, $minutes |
cache.deletecache.delete | $key$key |
connection.{name}.beganTransactionconnection.{name}.beganTransaction | $connection$connection |
connection.{name}.committedconnection.{name}.committed | $connection$connection |
connection.{name}.rollingBackconnection.{name}.rollingBack | $connection$connection |
illuminate.queryilluminate.query | $query, $bindings, $time, $connectionName$query, $bindings, $time, $connectionName |
illuminate.queue.afterilluminate.queue.after | $connection, $job, $data$connection, $job, $data |
illuminate.queue.failedilluminate.queue.failed | $connection, $job, $data$connection, $job, $data |
illuminate.queue.stoppingilluminate.queue.stopping | nullnull |
mailer.sendingmailer.sending | $message$message |
router.matchedrouter.matched | $route, $request$route, $request |
composing:{view name}composing:{view name} | $view$view |
creating:{view name}creating:{view name} | $view$view |