Skip to main content
Domain events are how one part of the application reacts to another without depending on it. They’re also the main extension point for plugins that need to act when something happens.

Dispatching

Dispatch is synchronous: listeners run in order, in the current request, before the call returns.

Registering listeners

Three mechanisms feed the listener provider.

On the event class

The core uses attributes on the event itself:

Programmatically

Bootstrappers and plugins use the array mapper:

On the listener class

A #[Subscribe] attribute on the listener is supported by the provider, though the core registers its own listeners the other two ways.

Listeners

A listener is an invokable class, resolved from the container:

Matching uses instanceof

A listener registered for a class also receives its subclasses. That’s deliberate, and it has a sharp edge:
Registering one listener for both UserUpdatedEvent and EmailVerifiedEvent makes it run twice when an email is verified. Subscribe to the most general event you care about, and branch inside the listener if you need to tell them apart.

Catalog

All classes live under {Module}\Domain\Events.

User

Workspace

Billing

Content and configuration

Chatbot

Cron

What the core listens to

Most other events have no core listener: they exist so that plugins can react.

Guidelines

Dispatch after the change, not before, so listeners see the final state.
Keep listeners fast, and catch your own exceptions, since a failure propagates into the request that dispatched the event.
Don’t rely on listener order beyond priorities.
Remember entities aren’t flushed yet: a listener sees objects in memory, not rows.