acc-create-psr14-event-dispatcher
Generates PSR-14 Event Dispatcher implementation for PHP 8.5. Creates EventDispatcherInterface, ListenerProviderInterface, and StoppableEventInterface with event propagation. Includes unit tests.
Best use case
acc-create-psr14-event-dispatcher is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Generates PSR-14 Event Dispatcher implementation for PHP 8.5. Creates EventDispatcherInterface, ListenerProviderInterface, and StoppableEventInterface with event propagation. Includes unit tests.
Teams using acc-create-psr14-event-dispatcher should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/acc-create-psr14-event-dispatcher/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How acc-create-psr14-event-dispatcher Compares
| Feature / Agent | acc-create-psr14-event-dispatcher | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Generates PSR-14 Event Dispatcher implementation for PHP 8.5. Creates EventDispatcherInterface, ListenerProviderInterface, and StoppableEventInterface with event propagation. Includes unit tests.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# 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
<?php
declare(strict_types=1);
namespace App\Infrastructure\Event;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\EventDispatcher\ListenerProviderInterface;
use Psr\EventDispatcher\StoppableEventInterface;
final readonly class EventDispatcher implements EventDispatcherInterface
{
public function __construct(
private ListenerProviderInterface $listenerProvider,
) {
}
public function dispatch(object $event): object
{
foreach ($this->listenerProvider->getListenersForEvent($event) as $listener) {
if ($event instanceof StoppableEventInterface && $event->isPropagationStopped()) {
break;
}
$listener($event);
}
return $event;
}
}
```
## Template: Listener Provider
```php
<?php
declare(strict_types=1);
namespace App\Infrastructure\Event;
use Psr\EventDispatcher\ListenerProviderInterface;
final class ListenerProvider implements ListenerProviderInterface
{
/** @var array<class-string, array<callable>> */
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
<?php
declare(strict_types=1);
namespace App\Infrastructure\Event;
use Psr\EventDispatcher\StoppableEventInterface;
abstract class StoppableEvent implements StoppableEventInterface
{
private bool $propagationStopped = false;
public function isPropagationStopped(): bool
{
return $this->propagationStopped;
}
public function stopPropagation(): void
{
$this->propagationStopped = true;
}
}
```
## Template: Domain Event
```php
<?php
declare(strict_types=1);
namespace App\Domain\User\Event;
use App\Domain\User\ValueObject\UserId;
use DateTimeImmutable;
final readonly class UserCreated
{
public function __construct(
public UserId $userId,
public string $email,
public DateTimeImmutable $occurredAt = new DateTimeImmutable(),
) {
}
}
```
## Template: Event Listener
```php
<?php
declare(strict_types=1);
namespace App\Application\User\Listener;
use App\Domain\User\Event\UserCreated;
use Psr\Log\LoggerInterface;
final readonly class SendWelcomeEmailListener
{
public function __construct(
private EmailServiceInterface $emailService,
private LoggerInterface $logger,
) {
}
public function __invoke(UserCreated $event): void
{
$this->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
<?php
declare(strict_types=1);
namespace App\Tests\Unit\Infrastructure\Event;
use App\Infrastructure\Event\EventDispatcher;
use App\Infrastructure\Event\ListenerProvider;
use App\Infrastructure\Event\StoppableEvent;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
#[Group('unit')]
#[CoversClass(EventDispatcher::class)]
final class EventDispatcherTest extends TestCase
{
#[Test]
public function it_dispatches_event_to_listeners(): void
{
$provider = new ListenerProvider();
$dispatcher = new EventDispatcher($provider);
$called = false;
$provider->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
<?php
use App\Infrastructure\Event\EventDispatcher;
use App\Infrastructure\Event\ListenerProvider;
// Setup
$provider = new ListenerProvider();
$dispatcher = new EventDispatcher($provider);
// Register listeners
$provider->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
<?php
declare(strict_types=1);
namespace App\Domain\User\Entity;
use App\Domain\User\Event\UserCreated;
use App\Domain\User\ValueObject\Email;
use App\Domain\User\ValueObject\UserId;
final class User
{
/** @var object[] */
private array $events = [];
private function __construct(
private readonly UserId $id,
private Email $email,
) {
}
public static function create(Email $email): self
{
$user = new self(UserId::generate(), $email);
$user->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 examplesRelated Skills
acc-create-test-builder
Generates Test Data Builder and Object Mother patterns for PHP 8.5. Creates fluent builders with sensible defaults and factory methods for test data creation.
acc-create-query
Generates CQRS Queries and Handlers for PHP 8.5. Creates read-only query DTOs with handlers that return data without side effects. Includes unit tests.
acc-create-psr18-http-client
Generates PSR-18 HTTP Client implementation for PHP 8.5. Creates ClientInterface with request sending and exception handling. Includes unit tests.
acc-create-entity
Generates DDD Entities for PHP 8.5. Creates identity-based objects with behavior, state transitions, and invariant protection. Includes unit tests.
acc-create-builder
Generates Builder pattern for PHP 8.5. Creates step-by-step object construction with fluent interface and validation. Includes unit tests.
acc-create-value-object
Generates DDD Value Objects for PHP 8.5. Creates immutable, self-validating objects with equality comparison. Includes unit tests.
acc-create-unit-test
Generates PHPUnit unit tests for PHP 8.5. Creates isolated tests with AAA pattern, proper naming, attributes, and one behavior per test. Supports Value Objects, Entities, Services.
acc-create-test-double
Generates test doubles (Mocks, Stubs, Fakes, Spies) for PHP 8.5. Creates appropriate double type based on testing needs with PHPUnit MockBuilder patterns.
acc-create-psr7-http-message
Generates PSR-7 HTTP Message implementations for PHP 8.5. Creates Request, Response, Stream, Uri, and ServerRequest classes with immutability. Includes unit tests.
acc-create-policy
Generates Policy pattern for PHP 8.5. Creates encapsulated business rules for authorization, validation, and domain constraints. Includes unit tests.
acc-create-null-object
Generates Null Object pattern for PHP 8.5. Creates safe default implementations eliminating null checks. Includes unit tests.
acc-create-command
Generates CQRS Commands and Handlers for PHP 8.5. Creates immutable command DTOs with handlers that modify state. Includes unit tests.