Previous pages provide the background on how to handle event messages in your application. The dispatching process is the starting point for event message. You will mostly send events after successfully handling Command Message, examples will base on that assumption.
You can inject EventBus and send events wherever necessary. Ecotone tries not to impose any specific solutions.
Event Bus
is special type of Messaging Gateway.
namespace Ecotone\Modelling;​interface EventBus{1 public function send(object $event);​2 public function sendWithMetadata(object $event, array $metadata);​3 public function convertAndSend(string $name, string $sourceMediaType, $data);​4 public function convertAndSendWithMetadata(string $name, string $sourceMediaType, $data, array $metadata);}
Event is routed to the Handler by class type.
use Ecotone\Modelling\Annotation\CommandHandler;use Ecotone\Modelling\EventBus;​class CloseTicketCommandHandler{/*** @CommandHandler()*/public function closeTicket(CloseTicketCommand $command, EventBus $eventBus) : void{// handle closing ticket​$eventBus->send(new TicketWasClosed($command->getTicketId()));}}
use Ecotone\Modelling\Annotation\EventHandler;​class NotificationService{/*** @EventHandler()*/public function closeTicket(TicketWasClosed $event) : void{// notify about closing the ticket}}
Does allow for passing extra meta information
, that can be used on targeted Event Handler
.
use Ecotone\Modelling\Annotation\CommandHandler;use Ecotone\Modelling\EventBus;​class CloseTicketCommandHandler{/*** @CommandHandler()*/public function closeTicket(CloseTicketCommand $command, EventBus $eventBus) : void{// handle closing ticket​$eventBus->sendWithMetadata(new TicketWasClosed($command->getTicketId()), ["executorUsername" => "someUsername"]);}}
use Ecotone\Modelling\Annotation\EventHandler;​class NotificationService{/*** @EventHandler()*/public function closeTicket(TicketWasClosed $event, array $metadata) : void{// you can use $metadata["executorUsername"]// notify about closing the ticket}}
Is used with Command Handlers,
routed by name and converted using Converter if needed.
Sending events by name instead of class type, may be found useful in integration with external application, when events are in different Media Type than PHP class.
use Ecotone\Modelling\Annotation\CommandHandler;use Ecotone\Modelling\EventBus;​class CloseTicketCommandHandler{/*** @CommandHandler()*/public function closeTicket(CloseTicketCommand $command, EventBus $eventBus) : void{// handle closing ticket​$eventBus->convertAndSend("ticket.wasClosed","application/json",'{"ticketId": 123}');}}
use Ecotone\Modelling\Annotation\EventHandler;​class NotificationService{/*** @EventHandler(listenTo="ticket.wasClosed")*/public function closeTicket(TicketWasClosed $event) : void{// notify about closing the ticket}}
JSON will be automatically converted to specific class type hinted
in method declaration of Event Handler. You could also use in here simple array
if you have JSON
to array
Converter or a string
, if you like to receive JSON string
.
Same as convertAndSend with possibility to pass Metadata.
use Ecotone\Modelling\Annotation\CommandHandler;use Ecotone\Modelling\EventBus;​class CloseTicketCommandHandler{/*** @CommandHandler()*/public function closeTicket(CloseTicketCommand $command, EventBus $eventBus) : void{// handle closing ticket​$eventBus->convertAndSendWithMetadata("ticket.wasClosed","application/json",'{"ticketId": 123}',["executorUsername" => "someUsername"]);}}
use Ecotone\Modelling\Annotation\EventHandler;​class NotificationService{/*** @EventHandler(listenTo="ticket.wasClosed")*/public function closeTicket(TicketWasClosed $event, array $metadata) : void{// you can use $metadata["executorUsername"]// notify about closing the ticket}}
Lazy Event Bus
is special type of Messaging Gateway.
namespace Ecotone\Modelling;​interface LazyEventBus{1 public function send(object $event);​2 public function sendWithMetadata(object $event, array $metadata);}
The difference between EventBus
and LazyEventBus
is the moment of EventHandler
invocation.
EventBus
sends Event right away to all awaiting EventHandlers
.
LazyEventBus
registers the Event and waiting for Command Handler
to finish. When the Command Handling is done, then it publish previously registered events.
Below we can comparison in execution order:
use Ecotone\Modelling\Annotation\CommandHandler;use Ecotone\Modelling\LazyEventBus;​class CloseTicketCommandHandler{/*** @CommandHandler()*/public function closeTicket(CloseTicketCommand $command, LazyEventBus $eventBus) : void{echo "starting command handler";$eventBus->send(new TicketWasClosed($command->getTicketId()));echo "finished command handler";}}​class NotificationService{/*** @EventHandler()*/public function closeTicket(TicketWasClosed $event) : void{echo "notification for event handler"}}​-----1. "starting command handler"2. "finished command handler"3. "notification for event handler"
use Ecotone\Messaging\Annotation\MessageEndpoint;use Ecotone\Modelling\Annotation\CommandHandler;use Ecotone\Modelling\LazyEventBus;​/*** @MessageEndpoint()*/class CloseTicketCommandHandler{/*** @CommandHandler()*/public function closeTicket(CloseTicketCommand $command, LazyEventBus $eventBus) : void{echo "starting command handler";$eventBus->send(new TicketWasClosed($command->getTicketId()));echo "finished command handler";}}​/*** @MessageEndpoint()*/class NotificationService{/*** @EventHandler()*/public function closeTicket(TicketWasClosed $event) : void{echo "notification for event handler"}}​-----1. "starting command handler"2. "notification for event handler"3. "finished command handler"
Does work the same as Send with possibility to send Metadata
. Usage is no different than with standard Event Bus.
The easiest way to publish events from aggregate would be to inject EventBus
into it's Command Handling
method. That would works, however there is a better solution.
Ecotone
does provide possibility to automatically gather events from Aggregate
and publish them using EventBus.
To tell Ecotone
, which method it should use for retrieving Event objects when using State-Stored Aggregate mark method containing events with annotation @AggregateEvents.
After handling Command
or Event
on Aggregate
events will be published.
/*** @return object[]* @AggregateEvents()*/public function getRecordedEvents() : array
If you do want to bother with implementation you can make use of trait WithAggregateEvents
use Ecotone\Modelling\Annotation\AggregateEvents;
If you want to record event for publication just use record
method.
$this->record(new OrderWasPlaced());
Events will be automatically retrieved and published after handling current Command or Event.
When using Event Sourcing Aggregate you do not need to do anything extra. Each method should return events after handling, those events will automatically published using Event Bus.
public function assignWorker(AssignWorkerCommand $command) : array