はじめに

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

イベントは、アプリケーションのさまざまな側面を切り離すための優れた方法です。なぜなら、単一のイベントには互いに依存しない複数のリスナーが存在できるからです。たとえば、注文が発送されるたびにユーザーにSlack通知を送信したい場合、注文処理コードをSlack通知コードに結びつけるのではなく、リスナーが受信し、Slack通知を送信するために使用できるApp\Events\OrderShippedイベントを発生させることができます。

イベントとリスナーの生成

イベントとリスナーを迅速に生成するには、make:eventおよびmake:listener Artisanコマンドを使用できます:

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

便利なことに、make:eventおよびmake:listener Artisanコマンドを追加の引数なしで呼び出すこともできます。その場合、Laravelは自動的にクラス名を尋ね、リスナーを作成する際にはリスナーがリッスンすべきイベントを尋ねます:

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

イベントとリスナーの登録

イベントの発見

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

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

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

  1. ->withEvents(discover: [
  2. __DIR__.'/../app/Domain/Orders/Listeners',
  3. ])
  1. ``````shell
  2. php artisan event:list
  3. `

本番環境でのイベントの発見

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

イベントの手動登録

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

クロージャリスナー

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

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

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

クロージャベースのイベントリスナーを登録する際、リスナーのクロージャをIlluminate\Events\queueable関数内にラップして、Laravelにリスナーをキューを使用して実行させることができます:

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

キューされたジョブのように、onConnectiononQueue、およびdelayメソッドを使用して、キューされたリスナーの実行をカスタマイズできます:

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

匿名のキューリスナーの失敗を処理したい場合、queueableリスナーを定義する際にcatchメソッドにクロージャを提供できます。このクロージャは、リスナーの失敗を引き起こしたイベントインスタンスとThrowableインスタンスを受け取ります:

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

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

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

イベントの定義

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

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

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

リスナーの定義

次に、例のイベントのリスナーを見てみましょう。イベントリスナーは、handleメソッドでイベントインスタンスを受け取ります。make:listener Artisanコマンドは、--eventオプションを指定して呼び出すと、適切なイベントクラスを自動的にインポートし、handleメソッドでイベントを型ヒントします。handleメソッド内で、イベントに応じて必要なアクションを実行できます:

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

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

イベントの伝播を停止する

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

キューされたイベントリスナー

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

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

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

それでおしまい!このリスナーによって処理されるイベントが発生すると、リスナーはLaravelのキューシステムを使用して自動的にキューに入れられます。リスナーがキューによって実行される際に例外がスローされない場合、キューされたジョブは処理が完了した後に自動的に削除されます。

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

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

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

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

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

条件付きでリスナーをキューに入れる

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

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

キューとの手動インタラクション

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

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

キューされたイベントリスナーとデータベーストランザクション

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

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

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

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

失敗したジョブの処理

時には、キューされたイベントリスナーが失敗することがあります。キューリスナーがキューワーカーによって定義された最大試行回数を超えると、failedメソッドがリスナーで呼び出されます。failedメソッドは、イベントインスタンスと失敗を引き起こしたThrowableを受け取ります:

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

キューリスナーの最大試行回数の指定

キューリスナーの1つがエラーに遭遇している場合、それが無限に再試行されることは望ましくありません。したがって、Laravelはリスナーが何回またはどのくらいの期間試行されるかを指定するさまざまな方法を提供します。

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

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

リスナーが失敗する前に何回試行されるかを定義する代わりに、リスナーがもはや試行されない時点を定義できます。これにより、リスナーは指定された時間枠内で何回でも試行されることができます。リスナーがもはや試行されない時点を定義するには、リスナークラスにretryUntilメソッドを追加します。このメソッドはDateTimeインスタンスを返す必要があります:

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

イベントの発行

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

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

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

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

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

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

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

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

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

イベントサブスクライバー

イベントサブスクライバーの作成

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

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

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

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

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

サブスクライバーを書いた後、Laravelは、Laravelのイベント発見規約に従っている場合、サブスクライバー内のハンドラーメソッドを自動的に登録します。そうでない場合、subscribeメソッドを使用してサブスクライバーを手動で登録できます。通常、これはアプリケーションのAppServiceProviderメソッド内で行うべきです:

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

テスト

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

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

特定の「真実テスト」を通過するイベントが発行されたことを確認するために、assertDispatchedまたはassertNotDispatchedメソッドにクロージャを渡すことができます。指定された真実テストを通過するイベントが少なくとも1つ発行された場合、アサーションは成功します:

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

特定のイベントに対してリスナーがリッスンしていることを確認したい場合、assertListeningメソッドを使用できます:

  1. Event::assertListening(
  2. OrderShipped::class,
  3. SendShipmentNotification::class
  4. );
  1. <a name="faking-a-subset-of-events"></a>
  2. ### イベントのサブセットをフェイクする
  3. 特定のイベントのセットに対してのみイベントリスナーをフェイクしたい場合、`````fake`````または`````fakeFor`````メソッドに渡すことができます:
  4. ``````php
  5. test('orders can be processed', function () {
  6. Event::fake([
  7. OrderCreated::class,
  8. ]);
  9. $order = Order::factory()->create();
  10. Event::assertDispatched(OrderCreated::class);
  11. // Other events are dispatched as normal...
  12. $order->update([...]);
  13. });
  14. `
  1. /**
  2. * Test order process.
  3. */
  4. public function test_orders_can_be_processed(): void
  5. {
  6. Event::fake([
  7. OrderCreated::class,
  8. ]);
  9. $order = Order::factory()->create();
  10. Event::assertDispatched(OrderCreated::class);
  11. // Other events are dispatched as normal...
  12. $order->update([...]);
  13. }

指定されたイベントのセットを除くすべてのイベントをフェイクするには、exceptメソッドを使用します:

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

スコープ付きイベントフェイク

テストの一部に対してのみイベントリスナーをフェイクしたい場合、fakeForメソッドを使用できます:

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