Event Listeners in Laravel 11
Up to Laravel 10, Event Listeners had to be registered by adding them to the $listen property of the EventServiceProvider.
Since Laravel 11, though, this has changed: Laravel 11 primarily relies on Event Discovery, and if you want to manually register Events, you are encouraged to do this in the AppServiceProvider:
use App\Domain\Orders\Events\PodcastProcessed;
use App\Domain\Orders\Listeners\SendPodcastNotification;
use Illuminate\Support\Facades\Event;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Event::listen(
PodcastProcessed::class,
SendPodcastNotification::class,
);
}
A separate EventServiceProvider seemed to better encapsulate the event registration, but let’s leave that aside for a moment.
The thing that annoys me more becomes apparent if you need to register multiple listeners with the same event: The Event::listen method can only register one listener at a time, so this gets verbose really quickly:
use App\Domain\Orders\Events\PodcastProcessing;
use App\Domain\Orders\Listeners\CompressPodcast;
use App\Domain\Orders\Listeners\UploadPodcast;
use App\Domain\Orders\Listeners\AddToSubscriberLibraries;
use Illuminate\Support\Facades\Event;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Event::listen(
PodcastProcessing::class,
CompressPodcast::class,
);
Event::listen(
PodcastProcessing::class,
UploadPodcast::class,
);
Event::listen(
PodcastProcessing::class,
AddToSubscriberLibraries::class,
);
}
I’ve got some events that have 10+ listeners registered with them in some of my projects. Not great.
So, I’ve added the following to my AppServiceProvider to return to the old behaviour:
use App\Domain\Orders\Events\PodcastProcessing;
use App\Domain\Orders\Listeners\CompressPodcast;
use App\Domain\Orders\Listeners\UploadPodcast;
use App\Domain\Orders\Listeners\AddToSubscriberLibraries;
use Illuminate\Support\Facades\Event;
private $listen = [
PodcastProcessing::class => [
CompressPodcast::class,
UploadPodcast::class,
AddToSubscriberLibraries::class,
],
];
/**
* Bootstrap any application services.
*/
public function boot(): void
{
foreach ($this->listen as $event => $listeners) {
foreach ($listeners as $listener) {
Event::listen($event, $listener);
}
}
}
I’m not going to pretend this is a big deal, but to me this seems more convenient 🤷♂️.