Developing a Command Bus in PHP

Published on: 07 Jan 2018 By:
Miniature bus

In this series of blog posts I’ll be developing a PHP library with a Command Bus, Command Handling and Subscription features. The main goal of this series is to describe the entire process of developing such a composer package, including making it available on Packagist and implementing it in Laravel through a separate package.

What are Commands, Handlers, Buses and Subscribers?

Simply put, a Command is a DTO (Data Transfer Object) with the single purpose of containing the details of a message, in this case a Command telling the model code to do something. Commands can be implemented in several layers of a code base. Mostly the Application and the Domain layers. However, these posts focus on the domain layer and thus the Application will call the Domain command from a service or controller once implemented. Commands are immutable, meaning that their properties (the message details) are set once the Command is constructed and they cannot be changed.

As described in it’s name, a Command Handler handles the command. Therefore, a Command Handler will generally only have one notable method, named “handle” or something similar. However, most Command Handlers will have dependencies in their constructor as needed by the handle method such as repositories.

In few words, the Command Bus dispatches the Command to the Command Handler, whilst the Command Subscriber subscribes the Command and its corresponding Handler to the Command Bus so that it knows which Handler to call when a Command is initiated.

There’s so many similar libraries, why develop another one?

Good question 😊 There are in fact a multitude of similar packages that provide similar functions and I’ve used several of them in many a project, however, so far I haven’t found one that fits my code architecture and that does not have other dependencies which I don’t require in my projects. Also, I need this package as a component to include in another much larger Event Sourcing Framework project, not to mention that I get the opportunity to build this with you! 😊

I want this component to be simple and flexible when implemented in other frameworks such as Laravel and Symfony. Finally, I want to be able to initialise the component by simply passing an array of Commands and their Command Handlers to the Command Subscriber and the Command Bus. Similar to this:

// An array of commands with handlers.
$commandsWithHandlers = [
    \KeithMifsud\Example\Model\Command\DoSomething::class =>
        \KeithMifsud\Example\Model\Handler\DoSomething::class,

    \KeithMifsud\Example\Model\Command\DoSomethingElse::class =>
        \KeithMifsud\Example\Model\Handler\DoSomethingElse::class,
];

// Bootstraps the component (named it Admiral cause it's cool !!)
$commandBus = new \SwellPhp\Admiral\CommandBus(
    new \SwellPhp\Admiral\ArrayResolver($commandsWithHandlers)
);

// Instantiates the command.
$command = new \KeithMifsud\Example\Model\Command\DoSomething(
    'some',
    'parameters'
);

// Dispath a command and it will be handled in the backgound.
$commandBus->dispatch($command);

Further to the above basic example, I would also want to be able to automatically inject any Command Handler dependencies when using a framework’s application container such as the Laravel Service Container which I’ll explain in more at the end of this series.

Step by step guide into developing an Open Source PHP Composer Package for Admiral Command Component

Throughout this small series of blog posts, I will detail the process of developing this component from the initial project setup to its official release as follows:

Part 1. Developing a Command Bus in PHP.

Part 2. PHP Software Development workflow.

Part 3. The Development of the Command Handler Resolver using a TDD approach.

Part 4. The development of the Bus using a TDD approach.

Part 5. Packaging and versioning for composer including basic usage documentation.

Part 6. Releasing on Packagist.

Part 7. Developing a Laravel implementation.

 Share the word

Did you enjoy reading this? If so, don't be selfish! Share it. 😉

 Something to add or ask?