Recording events and handling them¶
While the command bus handles a command, certain events will take place. It might be important to record these events and, when the command has been fully handled, notify other parts of the system about the events that were recorded.
This can be accomplished by using message recorders. These are objects with the ability to record messages. From the outside these messages can be retrieved, and erased:
1 2 3 4 5 6 | interface ContainsRecordedMessages
{
public function recordedMessages();
public function eraseMessages();
}
|
Collecting events¶
Publicly¶
The default implementation, which has a public record()
method as
well, is the PublicMessageRecorder
:
1 2 3 4 5 6 7 8 9 10 | use SimpleBus\Message\Recorder\PublicMessageRecorder;
$publicMessageRecorder = new PublicMessageRecorder();
$event = new UserRegistered(...);
$publicMessageRecorder->record($event);
$recordedEvents = $publicMessageRecorder->recordedEvents();
// $recordedEvents is an array containing the previously recorded $event object
|
Privately¶
When you use domain events, your domain entities will generate events while you change them. You record those events inside the entity. Later, when the changes have been persisted and the database transaction has succeeded, you should collect the recorded events and handle them:
1 2 3 4 5 6 7 8 9 10 11 12 13 | $entity->changeSomething();
// $entity generates a SomethingChanged event and records it internally
// start transaction
$entityManager->persist($entity);
// commit transaction
$events = $entity->recordedEvents();
// handle the events
foreach ($events as $event) {
$eventBus->handle($event);
}
|
You can give your entities the ability to record their own events by
letting them implement the RecordsMessages
interface and using the
PrivateMessageRecorderCapabilities
trait:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | use SimpleBus\Message\Recorder\RecordsMessages;
use SimpleBus\Message\Recorder\PrivateMessageRecorderCapabilities;
class YourEntity implements RecordsMessages
{
use PrivateMessageRecorderCapabilities;
public function changeSomething()
{
...
$this->record(new SomethingChanged());
}
}
|
Handling events¶
Handling publicly recorded events¶
Events are recorded while a command is handled. We only want to handle the events themselves after the command has been completely and successfully been handled. The best option to accomplish this is to add a piece of middleware to the command bus. This middleware needs the message recorder to find out which events were recorded during the handling of a command, and it needs the event bus to actually handle the recorded events:
1 2 3 4 5 6 | use SimpleBus\Message\Recorder\HandlesRecordedMessagesMiddleware;
$commandBus->appendMiddleware(new HandlesRecordedMessagesMiddleware(
$publicMessageRecorder,
$eventBus
));
|
Make sure to add this middleware first, before adding any other middleware. Like mentioned before: we only want events to be handled when we know that everything else has gone well.
Only the command bus handled recorded events automatically
When using a standard setup (like described above), only the command bus automatically handles recorded events. If you want to dispatch new events in for example event subscribers, you shouldn’t record the event, but just inject the event bus as a constructor argument and let it handle the new event right-away.
Handling domain events¶
When you privately record events inside your domain entities, you need to collect those recorded events manually. Your database abstraction library, ORM or ODM probably offers a way to hook into the process of persisting the entities and collecting them somehow. After the command has been handled successfully and the transaction has been committed, you can iterate over those entities and collect their recorded events.
Handling domain events with Doctrine ORM
SimpleBus comes with a Doctrine ORM bridge. Using this package you can collect recorded events from Doctrine ORM entities. See its README file for further instructions.
Combining multiple message recorders¶
If you have multiple ways in which you record events, e.g. using the
PublicMessageRecorder
and using domain events, you can combine those
into one message recorder, which aggregates the recorded messages:
1 2 3 4 5 6 7 8 9 | use SimpleBus\Message\Recorder\AggregatesRecordedMessages;
$aggregatingMessageRecorder = new AggregatesRecordedMessages(
[
$publicMessageRecorder,
$domainEventsMessagesRecorder,
...
]
);
|
Finally, you can provide this aggregating message recorder to the
HandlesRecordedMessagesMiddleware
and it will act as if it is a
single message recorder.
1 2 3 4 | $commandBus->appendMiddleware(new HandlesRecordedMessagesMiddleware(
$aggregatingMessageRecorder,
$eventBus
));
|