waffle-commons/event-dispatcher

Event Dispatcher component for Waffle framework.

Maintainers

Package info

github.com/waffle-commons/event-dispatcher

pkg:composer/waffle-commons/event-dispatcher

Statistics

Installs: 1

Dependents: 1

Suggesters: 0

Stars: 0

Open Issues: 0

0.1.0-beta0 2026-05-16 14:51 UTC

This package is auto-updated.

Last update: 2026-05-16 15:49:50 UTC


README

PHP Version Require PHP CI codecov Latest Stable Version Latest Unstable Version Total Downloads Packagist License

Waffle Event Dispatcher Component

Release: v0.1.0-beta0 PSR Compliance: PSR-14 (Psr\EventDispatcher\EventDispatcherInterface, ListenerProviderInterface, StoppableEventInterface)

A minimal, attribute-driven PSR-14 dispatcher. The dispatcher itself is final readonly and stateless; the listener provider stores the listener map and supports priority ordering and #[AsEventListener] attribute discovery.

๐Ÿ“ฆ Installation

composer require waffle-commons/event-dispatcher

๐Ÿงฑ Surface

Class Role
Waffle\Commons\EventDispatcher\Dispatcher\EventDispatcher final readonly PSR-14 dispatcher. Walks listeners, respects StoppableEventInterface.
Waffle\Commons\EventDispatcher\Provider\ListenerProvider Listener registry. Manual registration via addListener(), or attribute scanning via register($object).
Waffle\Commons\EventDispatcher\Attribute\AsEventListener PHP 8 attribute marking a class or method as a listener.
Waffle\Commons\EventDispatcher\Event\AbstractStoppableEvent Convenience base implementing StoppableEventInterface.

๐Ÿš€ Manual registration

use Waffle\Commons\EventDispatcher\Dispatcher\EventDispatcher;
use Waffle\Commons\EventDispatcher\Provider\ListenerProvider;

$provider = new ListenerProvider();
$provider->addListener(UserRegistered::class, function (UserRegistered $event): void {
    // โ€ฆ
}, priority: 100); // higher priority = earlier

$dispatcher = new EventDispatcher($provider);
$event = $dispatcher->dispatch(new UserRegistered($userId));

๐Ÿท๏ธ Attribute-driven registration (#[AsEventListener])

The attribute is declared as:

#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
final readonly class AsEventListener
{
    public function __construct(
        public ?string $event = null,
        public int $priority = 0,
    ) {}
}

Method-level โ€” event class resolved from the parameter type-hint

final class AuditListener
{
    #[AsEventListener(priority: 50)]
    public function onUserRegistered(UserRegistered $event): void
    {
        // resolved automatically from the parameter type
    }
}

$provider->register(new AuditListener());

Class-level โ€” first public non-constructor method is the handler

#[AsEventListener(event: UserRegistered::class, priority: 50)]
final class WelcomeMailer
{
    public function send(UserRegistered $event): void { /* โ€ฆ */ }
}

$provider->register(new WelcomeMailer());

๐Ÿ›‘ Stoppable events

use Waffle\Commons\EventDispatcher\Event\AbstractStoppableEvent;

final class CancellableJob extends AbstractStoppableEvent
{
    public function __construct(public readonly string $jobId) {}
}

$provider->addListener(CancellableJob::class, function (CancellableJob $e): void {
    if ($shouldCancel) {
        $e->stopPropagation();
    }
});

The dispatcher honours isPropagationStopped() and breaks out of the listener loop.

๐Ÿ˜ PHP 8.5 features used

  • final readonly class EventDispatcher โ€” the dispatcher itself is immutable.
  • Constructor property promotion with explicit visibility on listeners.
  • Typed properties + parameters throughout.
  • Inheritance walks via native get_parent_class() (not reflection caches), so listener resolution against parent event types is O(depth) without warm-up cost.

๐Ÿงช Testing

docker exec -w /waffle-commons/event-dispatcher waffle-dev composer tests

๐Ÿ“„ License

MIT โ€” see LICENSE.md.