Collecting events and the event dispatching command bus
Matthias Noback
It was quite a ride so far. We have seen commands, command buses, events and event buses. We distilled some more knowledge about them while formulating answers to some interesting questions from readers.
Why you should not dispatch events while handling a command
In a previous post we discussed a sample event (the UserSignedUp
event):
class UserSignedUp implements Event
{
public function name()
{
return 'user_signed_up';
}
public function __construct($userId)
{
$this->userId = $userId;
}
public function userId()
{
return $this->userId;
}
}
An instance of such an event can be handed over to the event bus. It will look for any number of event handlers that
wants to be notified about the event. In the case of the UserSignedUp
event, one of the interested event handlers is
the SendWelcomeMailWhenUserSignedUp
handler:
class SendWelcomeMailWhenUserSignedUp implements EventHandler
{
...
public function handle(Event $event)
{
$user = $this->userRepository->getById($event->userId());
$this->userMailer->sendWelcomeMailTo($user);
}
}
The UserSignedUp
event occurs whenever a SignUpUser
command has been handled. We might be tempted to inject the
event bus into the command handler and let it handle the event immediately:
class SignUpHandler
{
public function __construct(EventBus $eventBus, ...)
{
$this->eventBus = $eventBus;
...
}
public function handle($command)
{
...
$this->userRepository->add($user);
$event = new UserSignedUp($user->id());
$this->eventBus->handle($event);
}
}
We should not forget however that this command is handled within a database transaction created by one of the command buses. And as I already mentioned, we don’t want the event to be handled within the same transaction, since it could endanger the success of that transaction. Also, when the transaction fails in the end, we might end up handling an event for entities whose actual state is insecure.
So instead, we should merely collect events while handling the command and only hand them over to the event bus when the transaction was committed, i.e. when we know that the command has been successfully and completely handled.
Event providers
Of course, SimpleBus
would not be complete without an out-of-the-box implementation of this kind of delayed event
handling. The connecting concept between events and the command bus is the ProvidesEvents
interface, which is part of
the SimpleBus/EventBus package.
namespace SimpleBus\Event\Provider;
use SimpleBus\Event\Event;
interface ProvidesEvents
{
/**
* @return Event[]
*/
public function releaseEvents();
}
You can provide a simple implementation for such an EventProvider
by defining a class for it, which uses the trait
EventProviderCapabilities
. This adds the ability to collect events (using the raise()
method) and release them
later, using the releaseEvents()
method:
use SimpleBus\Event\Provider\EventProviderCapabilities;
class EventProvider implements ProvidesEvents
{
use EventProviderCapabilities;
}
We could inject this EventProvider
into any command handler and use the raise()
method of the EventProvider
to
raise new events (which will not be handled right-away, but only stored in-memory):
class SignUpHandler
{
public function __construct(EventProvider $eventProvider, ...)
{
$this->eventProvider = $eventProvider;
...
}
public function handle($command)
{
...
$event = new UserSignedUp($user->id());
$this->eventProvider->raise($event);
}
}
Now, at what point could we safely release the events collected by the EventProvider
and hand those events over to the
event bus? The answer is: in yet another command bus! We simply wrap the new event-aware command bus which starts and
commits the database transaction. Only then can we be sure that the transaction was successful and we can proceed to
safely dispatch the collected events.
Since SimpleBus/CommandBus
and SimpleBus/EventBus
are stand-alone packages, I introduced a bridge package between
the two, SimpleBus/CommandEventBridge. It contains this class, which
is a CommandBus
, but asks the event provider to release its events, and lets the EventBus
instance handle them:
class DispatchesEvents implements CommandBus
{
use RemembersNext;
private $eventProvider;
private $eventBus;
public function __construct(ProvidesEvents $eventProvider, EventBus $eventBus)
{
$this->eventBus = $eventBus;
$this->eventProvider = $eventProvider;
}
public function handle(Command $command)
{
$this->next($command);
foreach ($this->eventProvider->releaseEvents() as $event) {
$this->eventBus->handle($event);
}
}
}
In a diagram this would look something like this (from left to right it shows you the passage of time):

Conclusion
After reading this series about command and event buses, you can start using commands to interact with your application and events to act upon the things that happened. Because both the command and the event bus are highly extensible you have many options for introducing more advanced behavior. You could think of:
- Collecting events in an store
- Handling commands asynchronously
- The same for events
- …
For now we are more or less done talking about command and event buses. If you have questions, just write a comment below this post. I’m currently working on version 2.0 of the SimpleBus packages. You can at least expect a new post when I’m done, to announce the changes with respect to 1.0. To give you a sneak peek:
- Code for command and event buses will be generalized and bundled in the MessageBus package.
- Instead of wrapping message buses using composition, this new package introduces the concept of message bus middlewares, offering greater flexibility and cleaner code for your own specialized message bus features.