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.

16 stars

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

$curl -o ~/.claude/skills/acc-create-psr14-event-dispatcher/SKILL.md --create-dirs "https://raw.githubusercontent.com/diegosouzapw/awesome-omni-skill/main/skills/tools/acc-create-psr14-event-dispatcher/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/acc-create-psr14-event-dispatcher/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How acc-create-psr14-event-dispatcher Compares

Feature / Agentacc-create-psr14-event-dispatcherStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/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 examples

Related Skills

acc-create-test-builder

16
from diegosouzapw/awesome-omni-skill

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

16
from diegosouzapw/awesome-omni-skill

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

16
from diegosouzapw/awesome-omni-skill

Generates PSR-18 HTTP Client implementation for PHP 8.5. Creates ClientInterface with request sending and exception handling. Includes unit tests.

acc-create-entity

16
from diegosouzapw/awesome-omni-skill

Generates DDD Entities for PHP 8.5. Creates identity-based objects with behavior, state transitions, and invariant protection. Includes unit tests.

acc-create-builder

16
from diegosouzapw/awesome-omni-skill

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

16
from diegosouzapw/awesome-omni-skill

Generates DDD Value Objects for PHP 8.5. Creates immutable, self-validating objects with equality comparison. Includes unit tests.

acc-create-unit-test

16
from diegosouzapw/awesome-omni-skill

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

16
from diegosouzapw/awesome-omni-skill

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

16
from diegosouzapw/awesome-omni-skill

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

16
from diegosouzapw/awesome-omni-skill

Generates Policy pattern for PHP 8.5. Creates encapsulated business rules for authorization, validation, and domain constraints. Includes unit tests.

acc-create-null-object

16
from diegosouzapw/awesome-omni-skill

Generates Null Object pattern for PHP 8.5. Creates safe default implementations eliminating null checks. Includes unit tests.

acc-create-command

16
from diegosouzapw/awesome-omni-skill

Generates CQRS Commands and Handlers for PHP 8.5. Creates immutable command DTOs with handlers that modify state. Includes unit tests.