What is a command bus? A command... "...an object is used to encapsulate all information needed to perform an action..." ...and a bus "...a communication system that transfers data between components..."
A use case A Finder-like application in javascript On each file, you can operate commands: create a folder, rename a file, remove... Requests are sent from the JS application to a Symfony backend
Setting up a command bus We will use Tactician (https://tactician.thephpleague.com/) Developed by Ross Tuck A Symfony bundle is available Notable alternatives include SimpleBus, by Matthias Noback
A Command namespace AppBundle\Model\Command; use AppBundle\Entity\Item; class RemoveCommand { private $item; public function __construct(Item $item) { $this->item = $item; } public function getItem(): Item { return $this->item; } }
The corresponding handler namespace AppBundle\Handler; use AppBundle\Entity\Item; use AppBundle\Model\Command\RemoveCommand; class RemoveHandler { private $entityManager; // To inject public function handle(RemoveCommand $removeCommand): string { $item = $removeCommand->getItem(); $this->entityManager->remove($item); $this->entityManager->flush(); // We can find a better way return $item->getUuid(); // It can return a result! } }
Sending the command to the bus From the Symfony API controller: Great, Romaric... but what is the interest? /** * @ParamConverter("item") */ public function apiAction(Item $item) { $command = new RemoveCommand($item); $uuid = $this->get('tactician.commandbus')->handle($command); return new JsonResponse(['uuid' => $uuid]); }
Middleware examples Doctrine (https://tactician.thephpleague.com/plugins/doctrine/) : wraps handlers in a DB transaction Logger (https://tactician.thephpleague.com/plugins/logger/) : can log everything to Monolog (audit!) Validation (shipped with Symfony Tactician bundle) Security, authorization ...
Going further Testing: handlers and middlewares are easier to unit test Commands could be sent to a message queue (RabbitMQ...) instead of staying in memory, or scheduled to be executed later (delayed task...).