Як я помітила дублювання listener
Після реєстрації власної події я перевірила список подій і listeners:
php artisan event:listВласна подія була підключена правильно:
App\Modules\Auth\Domain\Event\UserRegistered└── App\Modules\Notification\Application\Listener\ DispatchNotificationsAfterUserRegistrationListenerАле нижче я побачила три однакові listeners для стандартної Laravel-події Registered:
Illuminate\Auth\Events\Registered├── Illuminate\Auth\Listeners\SendEmailVerificationNotification├── Illuminate\Auth\Listeners\SendEmailVerificationNotification└── Illuminate\Auth\Listeners\SendEmailVerificationNotificationПерша підозра - event cache
Першою думкою був застарілий кеш подій. Я очистила event cache і всі bootstrap caches:
php artisan event:clearphp artisan optimize:clear php artisan event:list \ | grep -A 4 "Illuminate\\\\Auth\\\\Events\\\\Registered"Але результат не змінився. SendEmailVerificationNotification усе ще був зареєстрований тричі.
Це означало, що проблема виникала під час завантаження застосунку, а не через старий кеш.
Звідки взялася повторна реєстрація
У bootstrap/providers.php у мене були зареєстровані два модульні event providers:
return [ App\Providers\AppServiceProvider::class, App\Modules\Media\Provider\MediaEventProvider::class, App\Modules\Notification\Provider\NotificationEventServiceProvider::class,];Обидва класи наслідували стандартний Laravel EventServiceProvider:
use Illuminate\Foundation\Support\Providers\EventServiceProvider; final class MediaEventProvider extends EventServiceProvider{ protected $listen = [ // Media events... ];}use Illuminate\Foundation\Support\Providers\EventServiceProvider; final class NotificationEventServiceProvider extends EventServiceProvider{ protected $listen = [ UserRegistered::class => [ DispatchNotificationsAfterUserRegistrationListener::class, ], ];}Чому дублювався саме listener підтвердження email
Проблема була не в масивах $listen.
Кожен модульний provider успадковував додаткову системну поведінку Laravel EventServiceProvider. Під час реєстрації такого provider Laravel також налаштовував стандартний listener для email verification.
Спрощено ця поведінка виглядала так:
Registered::class => SendEmailVerificationNotification::class;У результаті listener реєструвався:
стандартною конфігурацією Laravel;
під час завантаження MediaEventProvider;
під час завантаження NotificationEventServiceProvider.
Саме тому event:list показував три однакові записи.
Окремий EventServiceProvider для модулів
<?php declare(strict_types=1); namespace App\Modules\Core\Provider; use Illuminate\Foundation\Support\Providers\EventServiceProvider; abstract class ModuleEventServiceProvider extends EventServiceProvider{ /** * Module providers must not register Laravel's * global email verification listener. */ protected function configureEmailVerification(): void { // Intentionally left blank. }}Після цього модульні event providers почали наслідувати новий базовий клас.
use App\Modules\Core\Provider\ModuleEventServiceProvider; final class MediaEventProvider extends ModuleEventServiceProvider{ protected $listen = [ MediaFolderItemsChangedEvent::class => [ SyncMediaFolderItemsCountListener::class, ], MediaUsageChangedEvent::class => [ SyncMediaUsageCountListener::class, ], ];}use App\Modules\Core\Provider\ModuleEventServiceProvider; final class NotificationEventServiceProvider extends ModuleEventServiceProvider{ protected $listen = [ UserRegistered::class => [ DispatchNotificationsAfterUserRegistrationListener::class, ], ];}Результат до і після виправлення

Після зміни успадкування я ще раз очистила кеші та перевірила список подій:
php artisan optimize:clear php artisan event:list \ | grep -A 4 "Illuminate\\\\Auth\\\\Events\\\\Registered"Чи потрібно змінювати всі service providers
Ні. Проблема стосувалася лише модульних класів, які наслідували Laravel EventServiceProvider.
Звичайний ServiceProvider не виконує автоматичне налаштування email verification, тому такі providers змінювати не потрібно.
use Illuminate\Support\ServiceProvider; final class NotificationServiceProvider extends ServiceProvider{ public function boot(): void { Notification::observe(NotificationObserver::class); }}Висновок
Це один із тих випадків, коли проста діагностична команда виявляється кориснішою за довгий пошук у коді. Я перевіряла новий UserRegistered listener, а в результаті знайшла причину, через яку стандартне підтвердження email могло запускатися кілька разів.



