First of all, create an abstract Entity of which they will inherit all domain events. This entity will be placed on a shared domain as it will be used in different contexts and of this example it will be placed in the writing layer as we implement CQRS.
src/Shared/Domain/Write/Event/DomainEvent.php
Create AggregateRoot Entity
Create an abstract class called AggregateRoot witch inherit all root entities. The AggregateRoot is used to define the main entity from aggregate and can store on memory and publish the domain events from the entity.
And create a simple root entity to use which uses the above class and record an event when construct. Firstly create a simple Event like a DTO called FooWasCreated.
Then can create a root entity to record the event and store it in memory when construct the entity.
src/Context/Foo/Domain/Write/Foo.php
NOTE:This entity must define as Doctrine mapping because when persist this entity trigger the events. In this example not define doctrine infrastructure layer to persist the entity, I think you can find a lot of tutorials about that and I don’t want to make this tutorial longer.
Define bus for events with messenger
Define the interface on a shared domain in the write layer.
src/Shared/Domain/Write/Bus/EventBus.php
Implement the interface with the concrete Symfony Messenger on the infrastructure layer. This bus is quite simple just has one method publish is responsible for dispatching messages on MessageBus.
To simplify the example I just define de basic configuration of the event bus but you should define the other bus like a query or command and the correct retry policy.
config/services.yaml
To simplify this example I just defined the minimum services definition for this case but you need to define your different services need for your application.
Create Doctrine Listener to publish DomainEvents when flush
The idea is quite simple when flush the entity the listener gets the entities to update from Doctrine UnitOfWork and publish the domain events if they have.
Once the events are published Symfony Messenger takes care of sending the Queue system.
In this example, you can see how to implement an EventBus with Symfony Messenger and implement doctrine listener to publish domain events on flush at RabbitMQ following clean architectures.