Skip to content

Command Bus

The Command Bus plugin dispatches commands (write operations) to their corresponding handlers, decoupling the issuer from the handler implementation.

Two adapters are available:

  • SyncCommandBus executes commands synchronously with automatic handler resolution.
  • TransactionalCommandBus wraps command execution in a database transaction (decorator pattern).

Why Use It

In CQRS architecture, write operations are represented as commands. The Command Bus provides a single dispatch point that resolves the appropriate handler based on naming convention (CreateBookCommandCreateBookHandler). This separation enables middleware insertion (transactions, logging) without modifying business logic.

Usage

The bus dispatches a command to its handler:

$command = new CreateBookCommand($id, $title, $author, $isbn);
$this->commandBus->dispatch($command);

Commands are immutable data objects representing the intention to change state:

final readonly class CreateBookCommand implements CommandInterface
{
    public function __construct(
        public IdInterface $id,
        public string $title,
        public string $author,
        public string $isbn
    ) {}
}

Handlers process commands and return nothing (void):

public function handle(CommandInterface $command): void
{
    $book = new Book($command->id, ...);
    $this->bookRepository->save($book);
    $this->eventBus->dispatch(new BookCreatedEvent(...));
}

Testing

The SyncCommandBus can be instantiated directly in tests. For integration testing, handlers are typically tested in isolation by mocking the repository and event bus dependencies.

See Also