As presented at Dutch PHP Conference 2015, an introduction to command buses, how to implement your own in PHP and why they're both useful but unimportant.
9. class BUYBUYBUYController
{
public function buyAction(Request $request)
{
$form = $this->getForm();
$form->bindTo($request);
if ($form->isTotallyValid()) {
$store->purchaseGame($gameId, $customerId);
return $this->redirect('thanks_for_money');
}
return ['so_many_errors' => $form->getAllTheErrors()];
}
}
10. class Store
{
public function purchaseGame($gameId, $customerId)
{
Assert::notNull($gameId);
Assert::notNull($customerId);
$this->security->allowsPurchase($customerId);
$this->logging->debug('purchasing game');
try {
$this->db->beginTransaction();
$purchase = new Purchase($gameId, $customerId);
$this->repository->add($purchase);
$this->db->commitTransaction();
} catch(Exception $e) {
$this->db->rollbackTransaction();
throw $e;
}
}
}
11. class Store
{
public function purchaseGame($gameId, $customerId)
{
$purchase = new Purchase($gameId, $customerId);
$this->repository->add($purchase);
}
}
41. class PurchaseGame
{
private $gameId;
private $customerId;
public function __construct($gameId, $customerId)
{
$this->gameId = $gameId;
$this->customerId = $customerId;
}
public function getGameId()
{
return $this->gameId;
}
public function getCustomerId()
{
return $this->customerId;
}
}
42. class PurchaseController
{
public function purchaseGameAction(Request $request)
{
$form = $this->createForm('purchase_game');
$form->bind($request);
if ($form->isValid()) {
$command = $form->getData();
}
}
}
62. class PurchaseController
{
public function purchaseGameAction()
{
// form stuff lol
$command = $form->getData();
$this->handler->handle($command);
}
}
Controller
Must be
the RIGHT handler
73. class CommandBus
{
private $handlers = [];
public function __construct($handlers) {
$this->handlers = $handlers;
}
public function handle($command)
{
$name = get_class($command);
if (!isset($this->handlers[$name])) {
throw new Exception("No handler for $name");
}
$this->handlers[$name]->handle($command);
}
}
78. class CommandBus
{
private $handlers = [];
public function __construct($handlers) {
$this->handlers = $handlers;
}
public function handle($command)
{
$name = get_class($command);
if (!isset($this->handlers[$name])) {
throw new Exception("No handler for $name");
}
$this->handlers[$name]->handle($command);
}
}
79. class CommandBus
{
private $handlers = [];
public function __construct($handlers) {
$this->handlers = $handlers;
}
public function handle($command)
{
$name = get_class($command);
if (!isset($this->handlers[$name])) {
throw new Exception("No handler for $name");
}
$this->handlers[$name]->execute($command);
}
}
80. class CommandBus
{
private $handlers = [];
public function __construct($handlers) {
$this->handlers = $handlers;
}
public function handle($command)
{
$name = get_class($command);
if (!isset($this->handlers[$name])) {
throw new Exception("No handler for $name");
}
$this->handlers[$name]->__invoke($command);
}
}
81. class CommandBus
{
private $handlers = [];
public function __construct($handlers) {
$this->handlers = $handlers;
}
public function handle($command)
{
$name = get_class($command);
if (!isset($this->handlers[$name])) {
throw new Exception("No handler for $name");
}
$methodName = 'handle'.$name;
$this->handlers[$name]->{$methodName}($command);
}
}
82. class CommandBus
{
private $handlers = [];
public function __construct($handlers) {
$this->handlers = $handlers;
}
public function handle($command)
{
$name = get_class($command);
if (!isset($this->handlers[$name])) {
throw new Exception("No handler for $name");
}
$this->handlers[$name]->handle($command);
}
}
83. class CommandBus
{
private $container = [];
public function __construct($container) {
$this->container = $container;
}
public function handle($command)
{
$name = get_class($command)."Handler";
if (!$this->container->has($name)) {
throw new Exception("No handler for $name");
}
$this->container->get($name)->handle($command);
}
}
96. class CommandBus
{
private $handlers = [];
public function __construct($handlers) {
$this->handlers = $handlers;
}
public function handle($command)
{
$name = get_class($command);
if (!isset($this->handlers[$name])) {
throw new Exception("No handler for $name");
}
$this->handlers[$name]->handle($command);
}
}
97. class MyCommandBus
{
private $handlers = [];
public function __construct($handlers) {
$this->handlers = $handlers;
}
public function handle($command)
{
$name = get_class($command);
if (!isset($this->handlers[$name])) {
throw new Exception("No handler for $name");
}
$this->handlers[$name]->handle($command);
}
}
98. class MyCommandBus implements CommandBus
{
private $handlers = [];
public function __construct($handlers) {
$this->handlers = $handlers;
}
public function handle($command)
{
$name = get_class($command);
if (!isset($this->handlers[$name])) {
throw new Exception("No handler for $name");
}
$this->handlers[$name]->handle($command);
}
}
117. class PurchaseGameHandler
{
public function handle(PurchaseGame $command)
{
$this->security->allowsPurchase($command->getCustomerId());
try {
$this->db->beginTransaction();
$purchase = new Purchase(
$command->getGameId(),
$command->getCustomerId()
);
$this->repository->add($purchase);
$this->db->commitTransaction();
} catch(Exception $e) {
$this->db->rollbackTransaction();
throw $e;
}
}
}
118. class PurchaseGameHandler
{
public function handle(PurchaseGame $command)
{
$this->security->allowsPurchase($command->getCustomerId());
$purchase = new Purchase(
$command->getGameId(),
$command->getCustomerId()
);
$this->repository->add($purchase);
}
}
127. class AllowedPurchaseDecorator implements CommandBus
{
private $security;
private $innerBus;
public function __construct($security, $innerBus)
{
$this->security = $security;
$this->innerBus = $innerBus;
}
public function handle($command)
{
if ($command instanceof PurchaseCommand) {
$this->security->allowPurchase($command->getCustomerId());
}
$this->innerBus->handle($command);
}
}
128. class PurchaseGameHandler
{
public function handle(PurchaseGame $command)
{
$this->security->allowsPurchase($command->getCustomerId());
$purchase = new Purchase(
$command->getGameId(),
$command->getCustomerId()
);
$this->repository->add($purchase);
}
}
129. class PurchaseGameHandler
{
public function handle(PurchaseGame $command)
{
$purchase = new Purchase(
$command->getGameId(),
$command->getCustomerId()
);
$this->repository->add($purchase);
}
}
130. class PurchaseGameHandler
{
public function handle(PurchaseGame $command)
{
$purchase = new Purchase(
$command->getGameId(),
$command->getCustomerId()
);
$this->repository->add($purchase);
}
}
Stop cutting!