andrewdyer / command-bus
A framework-agnostic PHP library for dispatching commands to handlers, with support for a configurable middleware pipeline
Requires
- php: ^8.3
- psr/log: ^3.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.75
- phpunit/phpunit: ^10.5
This package is auto-updated.
Last update: 2026-05-26 21:32:11 UTC
README
Command Bus
A framework-agnostic PHP library for dispatching commands to handlers, with support for a configurable middleware pipeline.
Introduction
This library provides a framework-agnostic command bus for PHP applications, dispatching commands to their registered handlers through a configurable middleware pipeline, with a PSR-3 compatible logging middleware included out of the box.
Prerequisites
Installation
composer require andrewdyer/command-bus
Getting Started
1. Create a command
Create a command as a plain class carrying the data required to perform an operation:
class CreateUserCommand { public function __construct( public readonly string $firstName, public readonly string $lastName, public readonly string $email, ) {} }
2. Create a handler
Create a handler with a handle() method that processes the command:
class CreateUserHandler { public function handle(CreateUserCommand $command): mixed { // Handle the command... return $user; } }
3. Create the command bus and register the handler
Create a CommandBus instance and register the handler against the command class it should handle:
use AndrewDyer\CommandBus\CommandBus; $bus = new CommandBus(); $bus->register(CreateUserCommand::class, new CreateUserHandler());
Usage
Once the command bus is configured, commands can be dispatched to their registered handlers. If no handler is registered for a given command, a HandlerNotFoundException is thrown.
Dispatching a command
$user = $bus->dispatch(new CreateUserCommand( firstName: 'John', lastName: 'Doe', email: 'john.doe@example.com', ));
Adding middleware
Middleware intercepts commands before they reach the handler, allowing cross-cutting concerns such as logging, transactions, or validation to be applied consistently across all commands.
Logging middleware
A LoggingMiddleware is included out of the box. It accepts any PSR-3 compatible logger and logs the command class name before and after dispatch:
use AndrewDyer\CommandBus\Middleware\LoggingMiddleware; $bus->addMiddleware(new LoggingMiddleware($logger));
Custom middleware
Custom middleware defines an execute() method that receives the command and a $next closure to pass control down the pipeline:
class TransactionMiddleware { public function execute(object $command, \Closure $next): mixed { // Begin transaction... try { $result = $next($command); } catch (\Throwable $e) { // Rollback transaction... throw $e; } // Commit transaction... return $result; } }
Middleware is executed in the order it is registered, so the first middleware added is the first to intercept the command:
$bus->addMiddleware(new TransactionMiddleware()); $bus->addMiddleware(new LoggingMiddleware($logger));
License
Licensed under the MIT license and is free for private or commercial projects.