Messagebus
A MessageBus (CommandBus, EventBus and QueryBus) implementation in PHP7
Install / Use
/learn @PHPMessageBus/MessagebusREADME
Message Bus
Implementation for the CommandBus, the QueryBus and the EventBus in PHP 7 and using PSR-11.
- Installation
- Introduction
- What is a Message Bus?
- What are its benefits?
- 1. CommandBus
- 2. QueryBus
- 3. EventBus
- 3.1 - Usage
- 3.1.1 - Create an Event
- 3.1.2 - Create an EventHandler
- 3.1.3 - (Optional) Set the EventHandler's Priority
- 3.1.4 - Register the EventHandler
- 3.1.5 - Setting up the EventBusMiddleware
- 3.1.6 - Registering the remaining EventBus classes
- 3.1.7 - Running the EventBus
- 3.1.8 - (Optional) Running the EventBus as a Queue
- 3.2 - Predefined Middlewares
- 3.3 - Custom Middlewares
- 3.1 - Usage
- 4 - Serializers
- Contribute
- Support
- Authors
- License
Installation
Use Composer to install the package:
$ composer require nilportugues/messagebus
Introduction
The idea of a message bus is that you create message objects that represent what you want your application to do. Then, you toss it into the bus and the bus makes sure that the message object gets to where it needs to go.
Easy right? Keep reading!
What is a Message Bus?
A Message Bus is a pipe of Messages. This implementation takes care of 3 types of messages, Commands, Queries and Events. While all look similar at first, their intent is different.
- Command: its intent is about expressing an order to the system and modifies its current state. User expects no response.
- Event: its intent is to express something that has already happened in the system, and record it. User expects no response.
- Query: its intent is about expressing a question to the system. User expects a response.
From this classification, one can spot that Command and Events can work together very well.
What are its benefits?
Given the nature of the message, implementing an interface, you may write behaviours that wrap the message to log, process or modify the response using the Decorator pattern. These are called Middleware.
For instance:
- Implementing task-based user-interfaces you can map concepts to Commands, Queries and Events easily.
- It allows you to easily write a logging system to know what's going, whether its a Command, a Query or an Event. It's possible.
To wrap-up, its benefits are:
- Encourages separation of concerns.
- Encourages single responsibility design.
1. CommandBus
1.1 - Usage
1.1.1 - Create a Command
<?php
use NilPortugues\MessageBus\CommandBus\Contracts\Command;
final class RegisterUser implements Command
{
private $username;
private $password;
private $emailAddress;
public function __construct(string $username, string $password, string $emailAddress)
{
$this->username = $username;
$this->password = $password;
$this->emailAddress = $emailAddress;
}
//getters...
}
1.1.2 - Create a CommandHandler
The Command Handler must implement the CommandHandler interface and implement the __invoke method.
For instance:
<?php
use NilPortugues\MessageBus\CommandBus\Contracts\CommandHandler;
use NilPortugues\MessageBus\CommandBus\Contracts\Command;
final class RegisterUserHandler implements CommandHandler
{
private $userRepository;
public function __construct($userRepository)
{
$this->userRepository = $userRepository;
}
public function __invoke(RegisterUser $command)
{
$user = new User(
$command->getUsername(),
$command->getPassword(),
$command->getEmail(),
);
$this->userRepository->save($user);
}
}
1.1.3 - Register the CommandHandler
I'm assuming you're using some kind Service Container. Now it's time to register your CommandHandler.
For instance, in a Psr\Container compliant Service Container, we can do this as follows:
<?php
//...your other registered classes
$container['RegisterUserHandler'] = function($container) {
return new RegisterUserHandler($container->get('UserRepository');
};
1.1.4 - Setting up the CommandBus
The Command Bus Middleware requires two classes to be injected. First one is the command translator, and second one the handler resolver.
CommandTranslator
Classes implementing this interface will provide the FQN for the Handler class given a Command.
This package provides an implementation, NilPortugues\MessageBus\CommandBus\Translator\AppendStrategy which basically appends the word Handler to the provided Command class.
For custom strategies, you may write your own implementing the NilPortugues\MessageBus\CommandBus\Contracts\CommandTranslator interface.
CommandHandlerResolver
Classes implementing this interface will be resolving the class for the instance required based on the output of the CommandTranslator used.
This package provides an implementation, NilPortugues\MessageBus\CommandBus\Resolver\PsrContainerResolver, that expects any Service Container implementing the Psr\Container interface.
For Symfony 2 and 3 framework users up to version 3.2, you should use Symfony Container: NilPortugues\MessageBus\CommandBus\Resolver\SymfonyContainerResolver. For Symfony 3.3 and up use the PSR-11 ContainerResolver class.
1.1.5 - Registering the remaining CommandBus classes
The minimum set up to get the Command Bus working is:
<?php
//...your other registered classes
$container['CommandTranslator'] = function($container) {
return new \NilPortugues\MessageBus\CommandBus\Translator\AppendStrategy('Handler');
};
$container['CommandHandlerResolver'] = function($container) {
return new \NilPortugues\MessageBus\CommandBus\Resolver\PsrContainerResolver($container);
};
$container['CommandBusMiddleware'] = function($container) {
return new \NilPortugues\MessageBus\CommandBus\CommandBusMiddleware(
$container->get('CommandTranslator'),
$container->get('CommandHandlerResolver'),
);
};
$container['CommandBus'] = function($container) {
return new \NilPortugues\MessageBus\CommandBus\CommandBus([
$container->get('CommandBusMiddleware'),
]);
};
If for instance, we want to log everything happening in the Command Bus, we'll add to the middleware list the logger middleware. This will wrap the Command Bus, being able to log before and after it ran, and if there was an error.
<?php
//...your other registered classes
$container['LoggerCommandBusMiddleware



