event
introduce
Register events and listeners
use App\Events\OrderShipped; use App\Listeners\SendShipmentNotification; /** * The event listener mappings for the application. * * @var array<class-string, array<int, class-string>> */ protected $listen = [ OrderShipped::class => [ SendShipmentNotification::class, ], ];
event:list The command can be used to display a list of all events and listeners registered by your application.
Generate events and listeners
php artisan event:generate
php artisan make:event PodcastProcessed php artisan make:listener SendPodcastNotification --event=PodcastProcessed
Manually register events
use App\Events\PodcastProcessed; use App\Listeners\SendPodcastNotification; use Illuminate\Support\Facades\Event; /** * Register any other events for your application. */ public function boot(): void { Event::listen( PodcastProcessed::class, [SendPodcastNotification::class, 'handle'] ); Event::listen(function (PodcastProcessed $event) { // ... }); }
use App\Events\PodcastProcessed; use function Illuminate\Events\queueable; use Illuminate\Support\Facades\Event; /** * Register any other events for your application. */ public function boot(): void { Event::listen(queueable(function (PodcastProcessed $event) { // ... })); }
Event::listen(queueable(function (PodcastProcessed $event) { // ... })->onConnection('redis')->onQueue('podcasts')->delay(now()->addSeconds(10)));
use App\Events\PodcastProcessed; use function Illuminate\Events\queueable; use Illuminate\Support\Facades\Event; use Throwable; Event::listen(queueable(function (PodcastProcessed $event) { // ... })->catch(function (PodcastProcessed $event, Throwable $e) { // The queued listener failed... }));
Event::listen('event.*', function (string $eventName, array $data) { // ... });
Event discovery
use App\Events\PodcastProcessed; class SendPodcastNotification { /** * Handle the given event. */ public function handle(PodcastProcessed $event): void { // ... } }
/** * Determine if events and listeners should be automatically discovered. */ public function shouldDiscoverEvents(): bool { return true; }
/** * Get the listener directories that should be used to discover events. * * @return array<int, string> */ protected function discoverEventsWithin(): array { return [ $this->app->path('Listeners'), ]; }
Define Events
<? php namespace App\Events; use App\Models\Order; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Queue\SerializesModels; class OrderShipped { use Dispatchable, InteractsWithSockets, SerializesModels; /** * Create a new event instance. */ public function __construct( public Order $order, ) {} }
Define Listener
<? php namespace App\Listeners; use App\Events\OrderShipped; class SendShipmentNotification { /** * Create the event listener. */ public function __construct() { // ... } /** * Handle the event. */ public function handle(OrderShipped $event): void { // Access the order using $event->order... } }
Your event listeners can also specify any dependencies they need in their constructors. All event listeners pass Laravel Service Container Resolves, so dependencies are automatically injected.
Queued event listeners
<? php namespace App\Listeners; use App\Events\OrderShipped; use Illuminate\Contracts\Queue\ShouldQueue; class SendShipmentNotification implements ShouldQueue { // ... }
<? php namespace App\Listeners; use App\Events\OrderShipped; use Illuminate\Contracts\Queue\ShouldQueue; class SendShipmentNotification implements ShouldQueue { /** * The name of the connection the job should be sent to. * * @var string|null */ public $connection = 'sqs'; /** * The name of the queue the job should be sent to. * * @var string|null */ public $queue = 'listeners'; /** * The time (seconds) before the job should be processed. * * @var int */ public $delay = 60; }
<? php namespace App\Listeners; use App\Events\OrderShipped; use Illuminate\Contracts\Queue\ShouldQueue; class SendShipmentNotification implements ShouldQueue { /** * The name of the connection the job should be sent to. * * @var string|null */ public $connection = 'sqs'; /** * The name of the queue the job should be sent to. * * @var string|null */ public $queue = 'listeners'; /** * The time (seconds) before the job should be processed. * * @var int */ public $delay = 60; }
<? php namespace App\Listeners; use App\Events\OrderCreated; use Illuminate\Contracts\Queue\ShouldQueue; class RewardGiftCard implements ShouldQueue { /** * Reward a gift card to the customer. */ public function handle(OrderCreated $event): void { // ... } /** * Determine whether the listener should be queued. */ public function shouldQueue(OrderCreated $event): bool { return $event->order->subtotal >= 5000; } }
Manual interaction with queues
<? php namespace App\Listeners; use App\Events\OrderShipped; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Queue\InteractsWithQueue; class SendShipmentNotification implements ShouldQueue { use InteractsWithQueue; /** * Handle the event. */ public function handle(OrderShipped $event): void { if (true) { $this->release(30); } } }
Queued event listeners and database transactions
<? php namespace App\Listeners; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Queue\InteractsWithQueue; class SendShipmentNotification implements ShouldQueue { use InteractsWithQueue; public $afterCommit = true; }
Processing failed jobs
<? php namespace App\Listeners; use App\Events\OrderShipped; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Queue\InteractsWithQueue; use Throwable; class SendShipmentNotification implements ShouldQueue { use InteractsWithQueue; /** * Handle the event. */ public function handle(OrderShipped $event): void { // ... } /** * Handle a job failure. */ public function failed(OrderShipped $event, Throwable $exception): void { // ... } }
<? php namespace App\Listeners; use App\Events\OrderShipped; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Queue\InteractsWithQueue; class SendShipmentNotification implements ShouldQueue { use InteractsWithQueue; /** * The number of times the queued listener may be attempted. * * @var int */ public $tries = 5; }
use DateTime; /** * Determine the time at which the listener should timeout. */ public function retryUntil(): DateTime { return now()->addMinutes(5); }
Event scheduling
<? php namespace App\Http\Controllers; use App\Events\OrderShipped; use App\Http\Controllers\Controller; use App\Models\Order; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; class OrderShipmentController extends Controller { /** * Ship the given order. */ public function store(Request $request): RedirectResponse { $order = Order::findOrFail($request->order_id); // Order shipment logic... OrderShipped::dispatch($order); return redirect('/orders'); } }
OrderShipped::dispatchIf($condition, $order); OrderShipped::dispatchUnless($condition, $order);
Event Subscriber
Write event subscriber
<? php namespace App\Listeners; use Illuminate\Auth\Events\Login; use Illuminate\Auth\Events\Logout; use Illuminate\Events\Dispatcher; class UserEventSubscriber { /** * Handle user login events. */ public function handleUserLogin(string $event): void {} /** * Handle user logout events. */ public function handleUserLogout(string $event): void {} /** * Register the listeners for the subscriber. */ public function subscribe(Dispatcher $events): void { $events->listen( Login::class, [UserEventSubscriber::class, 'handleUserLogin'] ); $events->listen( Logout::class, [UserEventSubscriber::class, 'handleUserLogout'] ); } }
<? php namespace App\Listeners; use Illuminate\Auth\Events\Login; use Illuminate\Auth\Events\Logout; use Illuminate\Events\Dispatcher; class UserEventSubscriber { /** * Handle user login events. */ public function handleUserLogin(string $event): void {} /** * Handle user logout events. */ public function handleUserLogout(string $event): void {} /** * Register the listeners for the subscriber. * * @return array<string, string> */ public function subscribe(Dispatcher $events): array { return [ Login::class => 'handleUserLogin', Logout::class => 'handleUserLogout', ]; } }
Register event subscribers
<? php namespace App\Providers; use App\Listeners\UserEventSubscriber; use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; class EventServiceProvider extends ServiceProvider { /** * The event listener mappings for the application. * * @var array */ protected $listen = [ // ... ]; /** * The subscriber classes to register. * * @var array */ protected $subscribe = [ UserEventSubscriber::class, ]; }
test
<? php namespace Tests\Feature; use App\Events\OrderFailedToShip; use App\Events\OrderShipped; use Illuminate\Support\Facades\Event; use Tests\TestCase; class ExampleTest extends TestCase { /** * Test order shipping. */ public function test_orders_can_be_shipped(): void { Event::fake(); // Perform order shipping... // Assert that an event was dispatched... Event::assertDispatched(OrderShipped::class); // Assert an event was dispatched twice... Event::assertDispatched(OrderShipped::class, 2); // Assert an event was not dispatched... Event::assertNotDispatched(OrderFailedToShip::class); // Assert that no events were dispatched... Event::assertNothingDispatched(); } }
Event::assertDispatched(function (OrderShipped $event) use ($order) { return $event->order->id === $order->id; });
Event::assertListening( OrderShipped::class, SendShipmentNotification::class );
call
Event::fake() No event listener will be executed after. Therefore, if your test uses an event dependent model factory, such as creating a UUID during model creation events, you should call the
Event::fake() 。
A subset of forgery events
/** * Test order process. */ public function test_orders_can_be_processed(): void { Event::fake([ OrderCreated::class, ]); $order = Order::factory()->create(); Event::assertDispatched(OrderCreated::class); // Other events are dispatched as normal... $order->update([...]); }
Event::fake()->except([ OrderCreated::class, ]);
Scope event forgery
<? php namespace Tests\Feature; use App\Events\OrderCreated; use App\Models\Order; use Illuminate\Support\Facades\Event; use Tests\TestCase; class ExampleTest extends TestCase { /** * Test order process. */ public function test_orders_can_be_processed(): void { $order = Event::fakeFor(function () { $order = Order::factory()->create(); Event::assertDispatched(OrderCreated::class); return $order; }); // Events are dispatched as normal and observers will run ... $order->update([...]); } }