Dispatching Commands
Commands PHP
Previous pages provide the background on how to handle command messages in your application. The dispatching process is the starting point for command message.

Command Bus

Command Bus is special type of Messaging Gateway.
1
namespace Ecotone\Modelling;
2
3
interface CommandBus
4
{
5
// 1
6
public function send(object $command, array $metadata = []) : mixed;
7
8
// 2
9
public function sendWithRouting(string $routingKey, mixed $command, string $commandMediaType = MediaType::APPLICATION_X_PHP, array $metadata = []) : mixed;
10
}
Copied!

Send method

Command is routed to the Handler by class type.
Symfony / Laravel
Lite
1
// Command Bus will be auto registered in Depedency Container.
2
class TicketController
3
{
4
private CommandBus $commandBus;
5
6
public function __construct(CommandBus $commandBus)
7
{
8
$this->commandBus = $commandBus;
9
}
10
11
public function closeTicketAction(Request $request) : Response
12
{
13
$this->commandBus->send(
14
new CloseTicketCommand($request->get("ticketId"))
15
);
16
}
17
}
Copied!
1
$commandBus = $messagingSystem->getCommandBus();
2
3
$commandBus->send(new CloseTicketCommand($ticketId));
Copied!
Command Handler
1
class CloseTicketCommandHandler
2
{
3
#[CommandHandler]
4
public function closeTicket(CloseTicketCommand $command)
5
{
6
// handle closing ticket
7
}
8
}
Copied!

Sending To Aggregate

Ecotone knows which instance of Ticket it should call by mapping the property.
Command
1
class CloseTicketCommand
2
{
3
private $ticketId;
4
}
Copied!
Command Handler
1
#[Aggregate]
2
class Ticket
3
{
4
#[AggregateIdentifier]
5
private $ticketId;
6
7
#[CommandHandler]
8
public function closeTicket(CloseTicketCommand $command)
9
{
10
// handle closing ticket
11
}
12
}
Copied!
If you want to know more about identifier correlation, you can read here.

Send With Metadata

Does allow for passing extra meta information, that can be used on targeted Command Handler.
Symfony / Laravel
Lite
1
class TicketController
2
{
3
private CommandBus $commandBus;
4
5
public function __construct(CommandBus $commandBus)
6
{
7
$this->commandBus = $commandBus;
8
}
9
10
public function closeTicketAction(Request $request, Security $security) : Response
11
{
12
$this->commandBus->sendWithMetadata(
13
new CloseTicketCommand($request->get("ticketId")),
14
["executorUsername" => $security->getUser()->getUsername()]
15
);
16
}
17
}
Copied!
1
$commandBus = $messagingSystem->getGatewayByName(CommandBus::class);
2
3
$commandBus->sendWithMetadata(
4
new CloseTicketCommand($ticketId),
5
["executorUsername" => $executorUsername]
6
);
Copied!
Command Handler
1
class CloseTicketCommandHandler
2
{
3
#[CommandHandler]
4
public function closeTicket(CloseTicketCommand $command, array $metadata)
5
{
6
$ticket = ; // get Ticket using command
7
8
if ($metadata["executorUsername"] !== $ticket->getOwner()) {
9
throw new \InvalidArgumentException("Insufficient permissions")
10
}
11
// handle closing ticket
12
}
13
}
Copied!

Send With Routing

Is used with Command Handlers, routed by name and converted using Converter if needed.
Symfony / Laravel
Lite
1
class TicketController
2
{
3
private CommandBus $commandBus;
4
5
public function __construct(CommandBus $commandBus)
6
{
7
$this->commandBus = $commandBus;
8
}
9
10
public function closeTicketAction(Request $request) : Response
11
{
12
$commandBus->convertAndSend("closeTicket", "application/json", '{"ticketId": 123}');
13
}
14
}
Copied!
1
$commandBus = $messagingSystem->getGatewayByName(CommandBus::class);
2
3
$commandBus->convertAndSend(
4
"closeTicket",
5
"application/json",
6
'{"ticketId": 123}'
7
);
Copied!
Command Handler
1
class CloseTicketCommandHandler
2
{
3
#[CommandHandler("closeTicket")]
4
public function closeTicket(CloseTicketCommand $command)
5
{
6
// handle closing ticket
7
}
8
}
Copied!

Sending To Aggregate

Ecotone knows which instance of Ticket it should call by mapping the property.
Command
1
class CloseTicketCommand
2
{
3
private $ticketId;
4
}
Copied!
Command Handler
1
#[Aggregate]
2
class Ticket
3
{
4
#[AggregateIdentifier]
5
private $ticketId;
6
7
#[CommandHandler("closeTicket")]
8
public function closeTicket(CloseTicketCommand $command)
9
{
10
// handle closing ticket
11
}
12
}
Copied!
You may also tell about the identifiers, when sending an command using meta data. Then you command does not need to include identifier.
1
public function controllerAction()
2
{
3
$this->commandBus->sendWithRouting("startPayment", metadata: ["aggregate.id" => 123])
4
}
Copied!
If you want to know more about identifier correlation, you can read here.