--- name: acc-create-psr14-event-dispatcher description: Generates PSR-14 Event Dispatcher implementation for PHP 8.5. Creates EventDispatcherInterface, ListenerProviderInterface, and StoppableEventInterface with event propagation. Includes unit tests. --- # PSR-14 Event Dispatcher Generator ## Overview Generates PSR-14 compliant event dispatcher for domain events and application events. ## When to Use - Implementing event-driven architecture - Domain event dispatching in DDD - Decoupling application components - Building CQRS systems ## Generated Components | Component | Description | Location | |-----------|-------------|----------| | EventDispatcher | Dispatches events | `src/Infrastructure/Event/` | | ListenerProvider | Provides listeners | `src/Infrastructure/Event/` | | Stoppable Event | Base stoppable event | `src/Infrastructure/Event/` | | Unit Tests | PHPUnit tests | `tests/Unit/Infrastructure/Event/` | ## Template: Event Dispatcher ```php listenerProvider->getListenersForEvent($event) as $listener) { if ($event instanceof StoppableEventInterface && $event->isPropagationStopped()) { break; } $listener($event); } return $event; } } ``` ## Template: Listener Provider ```php > */ private array $listeners = []; public function getListenersForEvent(object $event): iterable { $eventClass = $event::class; yield from $this->listeners[$eventClass] ?? []; foreach (class_parents($eventClass) as $parent) { yield from $this->listeners[$parent] ?? []; } foreach (class_implements($eventClass) as $interface) { yield from $this->listeners[$interface] ?? []; } } /** @param class-string $eventClass */ public function addListener(string $eventClass, callable $listener): void { $this->listeners[$eventClass][] = $listener; } } ``` ## Template: Stoppable Event ```php propagationStopped; } public function stopPropagation(): void { $this->propagationStopped = true; } } ``` ## Template: Domain Event ```php logger->info('Sending welcome email', [ 'user_id' => $event->userId->toString(), 'email' => $event->email, ]); $this->emailService->send( to: $event->email, subject: 'Welcome!', template: 'emails/welcome', ); } } ``` ## Template: Unit Test ```php addListener(TestEvent::class, function () use (&$called) { $called = true; }); $dispatcher->dispatch(new TestEvent()); self::assertTrue($called); } #[Test] public function it_stops_propagation_for_stoppable_events(): void { $provider = new ListenerProvider(); $dispatcher = new EventDispatcher($provider); $callCount = 0; $provider->addListener(TestStoppableEvent::class, function (TestStoppableEvent $e) use (&$callCount) { $callCount++; $e->stopPropagation(); }); $provider->addListener(TestStoppableEvent::class, function () use (&$callCount) { $callCount++; }); $dispatcher->dispatch(new TestStoppableEvent()); self::assertSame(1, $callCount); } #[Test] public function it_returns_event_after_dispatch(): void { $provider = new ListenerProvider(); $dispatcher = new EventDispatcher($provider); $event = new TestEvent(); $result = $dispatcher->dispatch($event); self::assertSame($event, $result); } } final class TestEvent {} final class TestStoppableEvent extends StoppableEvent {} ``` ## Usage Example ```php addListener( UserCreated::class, new SendWelcomeEmailListener($emailService, $logger), ); $provider->addListener( UserCreated::class, new CreateUserProfileListener($profileService), ); // Dispatch event (from domain entity or handler) $event = new UserCreated($userId, $email); $dispatcher->dispatch($event); ``` ## DDD Integration ```php events[] = new UserCreated($user->id, $email->toString()); return $user; } /** @return object[] */ public function pullEvents(): array { $events = $this->events; $this->events = []; return $events; } } ``` ## Requirements ```json { "require": { "psr/event-dispatcher": "^1.0" } } ``` ## See Also - `references/templates.md` - Priority provider, async dispatcher - `references/examples.md` - Integration examples