コンテンツへスキップ

イベント

イントロダクション

Laravelのイベントはシンプルなオブザーバーパターンの実装を提供しており、アプリケーション内で発生する様々なイベントを購読し、リッスンできます。イベントクラスは通常app/Eventsディレクトリに、リスナはapp/Listenersに保存されます。アプリケーションにこれらのディレクトリが表示されていなくても心配ありません。Artisanコンソールコマンドを使用してイベントとリスナを生成すると、自動的に作成されます。

イベントは、アプリケーションのさまざまな側面を分離するための優れた方法です。単一のイベントは、互いに依存しない複数のリスナを持つことができます。たとえば、注文が出荷されるたびにユーザーにSlack通知を送信したい場合があります。注文処理コードをSlack通知コードに結合する代わりに、App\Events\OrderShippedイベントを発行し、リスナがそれを受信してSlack通知をディスパッチできます。

イベントとリスナの生成

イベントとリスナを素早く生成するには、make:eventmake:listenerのArtisanコマンドを使用します。

1php artisan make:event PodcastProcessed
2 
3php artisan make:listener SendPodcastNotification --event=PodcastProcessed

利便性のために、make:eventmake:listenerのArtisanコマンドを引数なしで実行することもできます。その場合、Laravelは自動的にクラス名を尋ね、リスナを作成するときには、どのイベントをリッスンすべきかを尋ねます。

1php artisan make:event
2 
3php artisan make:listener

イベントとリスナの登録

イベントの自動検出

デフォルトで、LaravelはアプリケーションのListenersディレクトリをスキャンすることで、イベントリスナを自動的に見つけて登録します。Laravelはhandleまたは__invokeで始まるリスナクラスのメソッドを見つけると、メソッドのシグネチャでタイプヒントされているイベントのイベントリスナとしてこれらのメソッドを登録します。

1use App\Events\PodcastProcessed;
2 
3class SendPodcastNotification
4{
5 /**
6 * Handle the given event.
7 */
8 public function handle(PodcastProcessed $event): void
9 {
10 // ...
11 }
12}

PHPのUnion型を使用して、複数のイベントをリッスンできます。

1/**
2 * Handle the given event.
3 */
4public function handle(PodcastProcessed|PodcastPublished $event): void
5{
6 // ...
7}

リスナを別のディレクトリまたは複数のディレクトリに保存する予定がある場合は、アプリケーションのbootstrap/app.phpファイルのwithEventsメソッドを使用して、Laravelにそれらのディレクトリをスキャンするように指示できます。

1->withEvents(discover: [
2 __DIR__.'/../app/Domain/Orders/Listeners',
3])

*文字をワイルドカードとして使用すると、複数の類似したディレクトリでリスナをスキャンできます。

1->withEvents(discover: [
2 __DIR__.'/../app/Domain/*/Listeners',
3])

event:listコマンドは、アプリケーション内に登録されているすべてのリスナを一覧表示するために使用します。

1php artisan event:list

本番環境でのイベントの自動検出

アプリケーションの速度を向上させるために、optimizeまたはevent:cache Artisanコマンドを使用して、アプリケーションの全リスナのマニフェストをキャッシュする必要があります。通常、このコマンドはアプリケーションのデプロイプロセスの一部として実行してください。このマニフェストは、フレームワークがイベント登録プロセスを高速化するために使用します。event:clearコマンドは、イベントキャッシュを破棄するために使用できます。

イベントの手動登録

Eventファサードを使用して、アプリケーションのAppServiceProviderbootメソッド内でイベントとそれに対応するリスナを手動で登録できます。

1use App\Domain\Orders\Events\PodcastProcessed;
2use App\Domain\Orders\Listeners\SendPodcastNotification;
3use Illuminate\Support\Facades\Event;
4 
5/**
6 * Bootstrap any application services.
7 */
8public function boot(): void
9{
10 Event::listen(
11 PodcastProcessed::class,
12 SendPodcastNotification::class,
13 );
14}

event:listコマンドは、アプリケーション内に登録されているすべてのリスナを一覧表示するために使用します。

1php artisan event:list

クロージャリスナ

通常、リスナはクラスとして定義します。しかし、アプリケーションのAppServiceProviderbootメソッドでクロージャベースのイベントリスナを手動で登録することもできます。

1use App\Events\PodcastProcessed;
2use Illuminate\Support\Facades\Event;
3 
4/**
5 * Bootstrap any application services.
6 */
7public function boot(): void
8{
9 Event::listen(function (PodcastProcessed $event) {
10 // ...
11 });
12}

キュー投入可能な匿名イベントリスナ

クロージャベースのイベントリスナを登録するとき、リスナクロージャをIlluminate\Events\queueable関数でラップして、Laravelにキューを使用してリスナを実行するように指示できます。

1use App\Events\PodcastProcessed;
2use function Illuminate\Events\queueable;
3use Illuminate\Support\Facades\Event;
4 
5/**
6 * Bootstrap any application services.
7 */
8public function boot(): void
9{
10 Event::listen(queueable(function (PodcastProcessed $event) {
11 // ...
12 }));
13}

キュー投入するジョブと同様に、onConnectiononQueuedelayメソッドを使用して、キュー投入するリスナの実行をカスタマイズできます。

1Event::listen(queueable(function (PodcastProcessed $event) {
2 // ...
3})->onConnection('redis')->onQueue('podcasts')->delay(now()->addSeconds(10)));

匿名のキュー投入されたリスナの失敗を処理したい場合は、queueableリスナを定義する際にcatchメソッドにクロージャを渡してください。このクロージャは、イベントインスタンスとリスナの失敗の原因となったThrowableインスタンスを受け取ります。

1use App\Events\PodcastProcessed;
2use function Illuminate\Events\queueable;
3use Illuminate\Support\Facades\Event;
4use Throwable;
5 
6Event::listen(queueable(function (PodcastProcessed $event) {
7 // ...
8})->catch(function (PodcastProcessed $event, Throwable $e) {
9 // The queued listener failed...
10}));

ワイルドカードイベントリスナ

*文字をワイルドカードパラメータとして使用してリスナを登録することもでき、同じリスナで複数のイベントを捕捉できます。ワイルドカードリスナは、最初の引数としてイベント名を受け取り、2番目の引数としてイベントデータ配列全体を受け取ります。

1Event::listen('event.*', function (string $eventName, array $data) {
2 // ...
3});

イベントの定義

イベントクラスは、本質的にイベントに関連する情報を保持するデータコンテナです。たとえば、App\Events\OrderShippedイベントがEloquent ORMオブジェクトを受け取ると仮定しましょう。

1<?php
2 
3namespace App\Events;
4 
5use App\Models\Order;
6use Illuminate\Broadcasting\InteractsWithSockets;
7use Illuminate\Foundation\Events\Dispatchable;
8use Illuminate\Queue\SerializesModels;
9 
10class OrderShipped
11{
12 use Dispatchable, InteractsWithSockets, SerializesModels;
13 
14 /**
15 * Create a new event instance.
16 */
17 public function __construct(
18 public Order $order,
19 ) {}
20}

ご覧のとおり、このイベントクラスにはロジックは含まれていません。購入されたApp\Models\Orderインスタンスのコンテナです。イベントが使用するSerializesModelsトレイトは、PHPのserialize関数を使用してイベントオブジェクトがシリアライズされる場合、たとえばキュー投入するリスナを利用する場合などに、Eloquentモデルを適切にシリアライズします。

リスナの定義

次に、このイベント例のリスナを見てみましょう。イベントリスナは、handleメソッドでイベントインスタンスを受け取ります。--eventオプションを付けて実行するmake:listenerArtisanコマンドは、適切なイベントクラスを自動的にインポートし、handleメソッドでイベントをタイプヒントします。handleメソッド内で、イベントに応答するために必要なアクションを実行できます。

1<?php
2 
3namespace App\Listeners;
4 
5use App\Events\OrderShipped;
6 
7class SendShipmentNotification
8{
9 /**
10 * Create the event listener.
11 */
12 public function __construct() {}
13 
14 /**
15 * Handle the event.
16 */
17 public function handle(OrderShipped $event): void
18 {
19 // Access the order using $event->order...
20 }
21}

イベントリスナは、コンストラクタで必要な依存関係をタイプヒントすることもできます。すべてのイベントリスナはLaravelのサービスコンテナを介して依存解決されるため、依存関係は自動的に注入されます。

イベントの伝播の停止

場合によっては、他のリスナへのイベントの伝播を停止したいことがあります。そのためには、リスナのhandleメソッドからfalseを返します。

キュー投入するイベントリスナ

リスナがメール送信やHTTPリクエストなどの遅いタスクを実行する場合、リスナをキューに入れると有益です。キュー投入するリスナを使用する前に、キューを設定し、サーバまたはローカル開発環境でキューワーカを起動してください。

リスナをキューに入れることを指定するには、ShouldQueueインターフェイスをリスナクラスに追加します。make:listener Artisanコマンドで生成されたリスナには、すでにこのインターフェイスが現在の名前空間にインポートされているため、すぐに使用できます。

1<?php
2 
3namespace App\Listeners;
4 
5use App\Events\OrderShipped;
6use Illuminate\Contracts\Queue\ShouldQueue;
7 
8class SendShipmentNotification implements ShouldQueue
9{
10 // ...
11}

これで完了です。このリスナが処理するイベントが発行されると、リスナはLaravelのキューシステムを使用してイベントディスパッチャによって自動的にキューに入れられます。リスナがキューによって実行されるときに例外がスローされなければ、キューに入れられたジョブは処理が終了した後に自動的に削除されます。

キュー接続、名前、遅延のカスタマイズ

イベントリスナのキュー接続、キュー名、またはキューの遅延時間をカスタマイズしたい場合は、リスナクラスに$connection$queue、または$delayプロパティを定義します。

1<?php
2 
3namespace App\Listeners;
4 
5use App\Events\OrderShipped;
6use Illuminate\Contracts\Queue\ShouldQueue;
7 
8class SendShipmentNotification implements ShouldQueue
9{
10 /**
11 * The name of the connection the job should be sent to.
12 *
13 * @var string|null
14 */
15 public $connection = 'sqs';
16 
17 /**
18 * The name of the queue the job should be sent to.
19 *
20 * @var string|null
21 */
22 public $queue = 'listeners';
23 
24 /**
25 * The time (seconds) before the job should be processed.
26 *
27 * @var int
28 */
29 public $delay = 60;
30}

リスナのキュー接続、キュー名、または遅延を実行時に定義したい場合は、リスナにviaConnectionviaQueue、またはwithDelayメソッドを定義します。

1/**
2 * Get the name of the listener's queue connection.
3 */
4public function viaConnection(): string
5{
6 return 'sqs';
7}
8 
9/**
10 * Get the name of the listener's queue.
11 */
12public function viaQueue(): string
13{
14 return 'listeners';
15}
16 
17/**
18 * Get the number of seconds before the job should be processed.
19 */
20public function withDelay(OrderShipped $event): int
21{
22 return $event->highPriority ? 0 : 60;
23}

条件付きでリスナをキューへ投入

実行時にのみ利用可能なデータに基づいて、リスナをキューに入れるべきかどうかを判断する必要がある場合があります。これを実現するために、リスナにshouldQueueメソッドを追加して、リスナをキューに入れるべきかどうかを判断できます。shouldQueueメソッドがfalseを返す場合、リスナはキューに入れられません。

1<?php
2 
3namespace App\Listeners;
4 
5use App\Events\OrderCreated;
6use Illuminate\Contracts\Queue\ShouldQueue;
7 
8class RewardGiftCard implements ShouldQueue
9{
10 /**
11 * Reward a gift card to the customer.
12 */
13 public function handle(OrderCreated $event): void
14 {
15 // ...
16 }
17 
18 /**
19 * Determine whether the listener should be queued.
20 */
21 public function shouldQueue(OrderCreated $event): bool
22 {
23 return $event->order->subtotal >= 5000;
24 }
25}

キューを手動で操作する

リスナの基になるキュージョブのdeleteメソッドとreleaseメソッドに手動でアクセスする必要がある場合は、Illuminate\Queue\InteractsWithQueueトレイトを使用して行います。このトレイトは、生成されたリスナでデフォルトでインポートされており、これらのメソッドへのアクセスを提供します。

1<?php
2 
3namespace App\Listeners;
4 
5use App\Events\OrderShipped;
6use Illuminate\Contracts\Queue\ShouldQueue;
7use Illuminate\Queue\InteractsWithQueue;
8 
9class SendShipmentNotification implements ShouldQueue
10{
11 use InteractsWithQueue;
12 
13 /**
14 * Handle the event.
15 */
16 public function handle(OrderShipped $event): void
17 {
18 if (true) {
19 $this->release(30);
20 }
21 }
22}

キュー投入するイベントリスナとデータベーストランザクション

キュー投入するリスナがデータベーストランザクション内で発行されると、データベーストランザクションがコミットされる前にキューによって処理されてしまう可能性があります。この場合、データベーストランザクション中に行ったモデルやデータベースレコードへの更新が、まだデータベースに反映されていない可能性があります。さらに、トランザクション内で作成されたモデルやデータベースレコードが、データベースに存在しない可能性もあります。リスナがこれらのモデルに依存している場合、キュー投入するリスナをディスパッチするジョブが処理されるときに、予期しないエラーが発生する可能性があります。

キュー接続のafter_commit設定オプションがfalseに設定されている場合でも、リスナクラスにShouldQueueAfterCommitインターフェイスを実装することで、特定のキュー投入するリスナを、開いているすべてのデータベーストランザクションがコミットされた後にディスパッチするように指定できます。

1<?php
2 
3namespace App\Listeners;
4 
5use Illuminate\Contracts\Queue\ShouldQueueAfterCommit;
6use Illuminate\Queue\InteractsWithQueue;
7 
8class SendShipmentNotification implements ShouldQueueAfterCommit
9{
10 use InteractsWithQueue;
11}

これらの問題の回避策の詳細については、キュー投入するジョブとデータベーストランザクションに関するドキュメントを確認してください。

失敗したジョブの処理

キュー投入されたイベントリスナが失敗することがあります。キュー投入されたリスナがキューワーカによって定義された最大試行回数を超えた場合、リスナのfailedメソッドが呼び出されます。failedメソッドは、イベントインスタンスと失敗の原因となったThrowableを受け取ります。

1<?php
2 
3namespace App\Listeners;
4 
5use App\Events\OrderShipped;
6use Illuminate\Contracts\Queue\ShouldQueue;
7use Illuminate\Queue\InteractsWithQueue;
8use Throwable;
9 
10class SendShipmentNotification implements ShouldQueue
11{
12 use InteractsWithQueue;
13 
14 /**
15 * Handle the event.
16 */
17 public function handle(OrderShipped $event): void
18 {
19 // ...
20 }
21 
22 /**
23 * Handle a job failure.
24 */
25 public function failed(OrderShipped $event, Throwable $exception): void
26 {
27 // ...
28 }
29}

キュー投入するリスナの最大試行回数の指定

キュー投入するリスナの1つでエラーが発生した場合、無期限に再試行し続けることは望ましくないでしょう。そのため、Laravelは、リスナを何回、またはどのくらいの期間試行できるかを指定するためのさまざまな方法を提供しています。

リスナクラスに$triesプロパティを定義して、リスナが失敗したと見なされるまでに何回試行できるかを指定できます。

1<?php
2 
3namespace App\Listeners;
4 
5use App\Events\OrderShipped;
6use Illuminate\Contracts\Queue\ShouldQueue;
7use Illuminate\Queue\InteractsWithQueue;
8 
9class SendShipmentNotification implements ShouldQueue
10{
11 use InteractsWithQueue;
12 
13 /**
14 * The number of times the queued listener may be attempted.
15 *
16 * @var int
17 */
18 public $tries = 5;
19}

リスナが失敗するまでに何回試行できるかを定義する代わりに、リスナを試行すべきでなくなる時刻を定義することもできます。これにより、リスナは特定の期間内に何回でも試行できます。リスナを試行すべきでなくなる時刻を定義するには、リスナクラスにretryUntilメソッドを追加します。このメソッドはDateTimeインスタンスを返す必要があります。

1use DateTime;
2 
3/**
4 * Determine the time at which the listener should timeout.
5 */
6public function retryUntil(): DateTime
7{
8 return now()->addMinutes(5);
9}

キュー投入するリスナのバックオフの指定

例外に遭遇したリスナを再試行する前にLaravelが何秒待機するかを設定したい場合は、リスナクラスにbackoffプロパティを定義することで行えます。

1/**
2 * The number of seconds to wait before retrying the queued listener.
3 *
4 * @var int
5 */
6public $backoff = 3;

リスナのバックオフ時間を決定するためにより複雑なロジックが必要な場合は、リスナクラスにbackoffメソッドを定義できます。

1/**
2 * Calculate the number of seconds to wait before retrying the queued listener.
3 */
4public function backoff(): int
5{
6 return 3;
7}

backoffメソッドからバックオフ値の配列を返すことで、「指数関数的な」バックオフを簡単に設定できます。この例では、再試行の遅延は最初の再試行で1秒、2回目の再試行で5秒、3回目の再試行で10秒、それ以上の試行が残っている場合はそれ以降のすべての再試行で10秒になります。

1/**
2 * Calculate the number of seconds to wait before retrying the queued listener.
3 *
4 * @return array<int, int>
5 */
6public function backoff(): array
7{
8 return [1, 5, 10];
9}

イベントの発行

イベントを発行するには、イベントの静的dispatchメソッドを呼び出します。このメソッドは、Illuminate\Foundation\Events\Dispatchableトレイトによってイベントで利用可能になります。dispatchメソッドに渡される引数はすべて、イベントのコンストラクタに渡されます。

1<?php
2 
3namespace App\Http\Controllers;
4 
5use App\Events\OrderShipped;
6use App\Http\Controllers\Controller;
7use App\Models\Order;
8use Illuminate\Http\RedirectResponse;
9use Illuminate\Http\Request;
10 
11class OrderShipmentController extends Controller
12{
13 /**
14 * Ship the given order.
15 */
16 public function store(Request $request): RedirectResponse
17 {
18 $order = Order::findOrFail($request->order_id);
19 
20 // Order shipment logic...
21 
22 OrderShipped::dispatch($order);
23 
24 return redirect('/orders');
25 }
26}

条件付きでイベントを発行したい場合は、dispatchIfメソッドとdispatchUnlessメソッドを使用できます。

1OrderShipped::dispatchIf($condition, $order);
2 
3OrderShipped::dispatchUnless($condition, $order);

テスト時には、リスナを実際にトリガーせずに特定のイベントが発行されたことをアサートすると便利な場合があります。Laravelの組み込みテストヘルパを使えば、簡単です。

データベーストランザクション後のイベント発行

場合によっては、アクティブなデータベーストランザクションがコミットされた後にのみイベントをディスパッチするようにLaravelに指示したいことがあります。そのためには、イベントクラスにShouldDispatchAfterCommitインターフェイスを実装します。

このインターフェイスは、現在のデータベーストランザクションがコミットされるまでイベントをディスパッチしないようにLaravelに指示します。トランザクションが失敗した場合、イベントは破棄されます。イベントがディスパッチされたときにデータベーストランザクションが進行中でない場合、イベントはすぐにディスパッチされます。

1<?php
2 
3namespace App\Events;
4 
5use App\Models\Order;
6use Illuminate\Broadcasting\InteractsWithSockets;
7use Illuminate\Contracts\Events\ShouldDispatchAfterCommit;
8use Illuminate\Foundation\Events\Dispatchable;
9use Illuminate\Queue\SerializesModels;
10 
11class OrderShipped implements ShouldDispatchAfterCommit
12{
13 use Dispatchable, InteractsWithSockets, SerializesModels;
14 
15 /**
16 * Create a new event instance.
17 */
18 public function __construct(
19 public Order $order,
20 ) {}
21}

イベントサブスクライバ

イベントサブスクライバの記述

イベントサブスクライバは、サブスクライバクラス自体の中から複数のイベントを購読できるクラスであり、単一のクラス内に複数のイベントハンドラを定義できます。サブスクライバはsubscribeメソッドを定義する必要があり、これにはイベントディスパッチャインスタンスが渡されます。指定されたディスパッチャでlistenメソッドを呼び出して、イベントリスナを登録できます。

1<?php
2 
3namespace App\Listeners;
4 
5use Illuminate\Auth\Events\Login;
6use Illuminate\Auth\Events\Logout;
7use Illuminate\Events\Dispatcher;
8 
9class UserEventSubscriber
10{
11 /**
12 * Handle user login events.
13 */
14 public function handleUserLogin(Login $event): void {}
15 
16 /**
17 * Handle user logout events.
18 */
19 public function handleUserLogout(Logout $event): void {}
20 
21 /**
22 * Register the listeners for the subscriber.
23 */
24 public function subscribe(Dispatcher $events): void
25 {
26 $events->listen(
27 Login::class,
28 [UserEventSubscriber::class, 'handleUserLogin']
29 );
30 
31 $events->listen(
32 Logout::class,
33 [UserEventSubscriber::class, 'handleUserLogout']
34 );
35 }
36}

イベントリスナメソッドがサブスクライバ自体内で定義されている場合は、サブスクライバのsubscribeメソッドからイベントとメソッド名の配列を返すのがより便利でしょう。Laravelはイベントリスナを登録するときに、サブスクライバのクラス名を自動的に決定します。

1<?php
2 
3namespace App\Listeners;
4 
5use Illuminate\Auth\Events\Login;
6use Illuminate\Auth\Events\Logout;
7use Illuminate\Events\Dispatcher;
8 
9class UserEventSubscriber
10{
11 /**
12 * Handle user login events.
13 */
14 public function handleUserLogin(Login $event): void {}
15 
16 /**
17 * Handle user logout events.
18 */
19 public function handleUserLogout(Logout $event): void {}
20 
21 /**
22 * Register the listeners for the subscriber.
23 *
24 * @return array<string, string>
25 */
26 public function subscribe(Dispatcher $events): array
27 {
28 return [
29 Login::class => 'handleUserLogin',
30 Logout::class => 'handleUserLogout',
31 ];
32 }
33}

イベントサブスクライバの登録

サブスクライバを記述した後、Laravelのイベント自動検出規約に従っていれば、Laravelはサブスクライバ内のハンドラメソッドを自動的に登録します。そうでなければ、Eventファサードのsubscribeメソッドを使用してサブスクライバを手動で登録できます。通常、これはアプリケーションのAppServiceProviderbootメソッド内で行う必要があります。

1<?php
2 
3namespace App\Providers;
4 
5use App\Listeners\UserEventSubscriber;
6use Illuminate\Support\Facades\Event;
7use Illuminate\Support\ServiceProvider;
8 
9class AppServiceProvider extends ServiceProvider
10{
11 /**
12 * Bootstrap any application services.
13 */
14 public function boot(): void
15 {
16 Event::subscribe(UserEventSubscriber::class);
17 }
18}

テスト

イベントを発行するコードをテストする場合、Laravelにイベントのリスナを実際に実行しないように指示したい場合があります。リスナのコードは、対応するイベントを発行するコードとは別に直接テストできるからです。もちろん、リスナ自体をテストするには、リスナインスタンスを作成し、テストで直接handleメソッドを呼び出すことができます。

Eventファサードのfakeメソッドを使用すると、リスナの実行を防ぎ、テスト対象のコードを実行し、assertDispatchedassertNotDispatchedassertNothingDispatchedメソッドを使用してアプリケーションによってどのイベントが発行されたかをアサートできます。

1<?php
2 
3use App\Events\OrderFailedToShip;
4use App\Events\OrderShipped;
5use Illuminate\Support\Facades\Event;
6 
7test('orders can be shipped', function () {
8 Event::fake();
9 
10 // Perform order shipping...
11 
12 // Assert that an event was dispatched...
13 Event::assertDispatched(OrderShipped::class);
14 
15 // Assert an event was dispatched twice...
16 Event::assertDispatched(OrderShipped::class, 2);
17 
18 // Assert an event was not dispatched...
19 Event::assertNotDispatched(OrderFailedToShip::class);
20 
21 // Assert that no events were dispatched...
22 Event::assertNothingDispatched();
23});
1<?php
2 
3namespace Tests\Feature;
4 
5use App\Events\OrderFailedToShip;
6use App\Events\OrderShipped;
7use Illuminate\Support\Facades\Event;
8use Tests\TestCase;
9 
10class ExampleTest extends TestCase
11{
12 /**
13 * Test order shipping.
14 */
15 public function test_orders_can_be_shipped(): void
16 {
17 Event::fake();
18 
19 // Perform order shipping...
20 
21 // Assert that an event was dispatched...
22 Event::assertDispatched(OrderShipped::class);
23 
24 // Assert an event was dispatched twice...
25 Event::assertDispatched(OrderShipped::class, 2);
26 
27 // Assert an event was not dispatched...
28 Event::assertNotDispatched(OrderFailedToShip::class);
29 
30 // Assert that no events were dispatched...
31 Event::assertNothingDispatched();
32 }
33}

assertDispatchedまたはassertNotDispatchedメソッドにクロージャを渡して、特定の「真理値テスト」に合格するイベントがディスパッチされたことをアサートできます。指定された真理値テストに合格するイベントが少なくとも1つディスパッチされていれば、アサーションは成功します。

1Event::assertDispatched(function (OrderShipped $event) use ($order) {
2 return $event->order->id === $order->id;
3});

イベントリスナが特定のイベントをリッスンしていることを単にアサートしたい場合は、assertListeningメソッドを使用できます。

1Event::assertListening(
2 OrderShipped::class,
3 SendShipmentNotification::class
4);

Event::fake()を呼び出した後、イベントリスナは実行されません。したがって、モデルのcreatingイベント中にUUIDを作成するなど、イベントに依存するモデルファクトリをテストで使用する場合は、ファクトリを使用した後でEvent::fake()を呼び出す必要があります。

イベントの一部を偽装

特定のイベントセットに対してのみイベントリスナを偽装したい場合は、それらをfakeまたはfakeForメソッドに渡すことができます。

1test('orders can be processed', function () {
2 Event::fake([
3 OrderCreated::class,
4 ]);
5 
6 $order = Order::factory()->create();
7 
8 Event::assertDispatched(OrderCreated::class);
9 
10 // Other events are dispatched as normal...
11 $order->update([...]);
12});
1/**
2 * Test order process.
3 */
4public function test_orders_can_be_processed(): void
5{
6 Event::fake([
7 OrderCreated::class,
8 ]);
9 
10 $order = Order::factory()->create();
11 
12 Event::assertDispatched(OrderCreated::class);
13 
14 // Other events are dispatched as normal...
15 $order->update([...]);
16}

exceptメソッドを使用して、指定したイベントのセットを除くすべてのイベントを偽装できます。

1Event::fake()->except([
2 OrderCreated::class,
3]);

スコープ付きイベント偽装

テストの一部に対してのみイベントリスナを偽装したい場合は、fakeForメソッドを使用できます。

1<?php
2 
3use App\Events\OrderCreated;
4use App\Models\Order;
5use Illuminate\Support\Facades\Event;
6 
7test('orders can be processed', function () {
8 $order = Event::fakeFor(function () {
9 $order = Order::factory()->create();
10 
11 Event::assertDispatched(OrderCreated::class);
12 
13 return $order;
14 });
15 
16 // Events are dispatched as normal and observers will run ...
17 $order->update([...]);
18});
1<?php
2 
3namespace Tests\Feature;
4 
5use App\Events\OrderCreated;
6use App\Models\Order;
7use Illuminate\Support\Facades\Event;
8use Tests\TestCase;
9 
10class ExampleTest extends TestCase
11{
12 /**
13 * Test order process.
14 */
15 public function test_orders_can_be_processed(): void
16 {
17 $order = Event::fakeFor(function () {
18 $order = Order::factory()->create();
19 
20 Event::assertDispatched(OrderCreated::class);
21 
22 return $order;
23 });
24 
25 // Events are dispatched as normal and observers will run ...
26 $order->update([...]);
27 }
28}

Laravelは最も生産的な方法です
ソフトウェアを構築、デプロイ、監視します。