Core

Event Service Provider

Synchronous event dispatcher and listener registration infrastructure.

Responsibility

Registers EventDispatcherInterface and alias events for decoupled domain/application event handling. EventServiceProvider also reads listener definitions from EventsConfig and registers them on the dispatcher.

Listener config

Application listeners are configured in app/Config/Events.yaml. Event class names map to listener class strings in YAML, and the loader converts that payload into typed EventsConfigDefinition before EventServiceProvider registers listeners on the dispatcher.

example.php
module: events
config:
  listeners:
    App\Events\UserRegisteredEvent:
      - App\Listeners\SendWelcomeEmailListener

Event DTO

Events are plain objects. Keep them small and explicit; they should carry data, not framework dependencies.

example.php
namespace App\Events;

final class UserRegisteredEvent
{
    public function __construct(
        private readonly string $email,
    ) {}

    public function email(): string
    {
        return $this->email;
    }
}

Listener

A listener can be any callable. Class-string listeners are resolved through the container, so listener classes can use constructor injection when registered as services or autowired by the container.

example.php
namespace App\Listeners;

use App\Events\UserRegisteredEvent;

final class SendWelcomeEmailListener
{
    public function __invoke(UserRegisteredEvent $event): void
    {
        // Handle event here.
    }
}

Dispatching

Prefer constructor injection in services/controllers. Direct container access is useful in factories or examples where the container is already available.

example.php
use App\Events\UserRegisteredEvent;
use Lemonade\Framework\Event\EventDispatcherInterface;

final class ExampleService
{
    public function __construct(
        private readonly EventDispatcherInterface $events,
    ) {}

    public function run(): void
    {
        $this->events->dispatch(new UserRegisteredEvent('user@example.test'));
    }
}

Runtime behavior

Events are synchronous: dispatch() invokes matching listeners before returning the event object. The dispatcher matches listeners registered for the exact event class, parent classes and implemented interfaces. Listener priority is available programmatically through addListener($eventClass, $listener, priority: 10); EventsConfigDefinition registers listeners with default priority.

Events are not queue

EventServiceProvider does not make work asynchronous. Use events for in-process decoupling. For background jobs, retries or workers, use QueueBusInterface and QueueServiceProvider instead.