CQRS Scaffolding

The eventsourcerer/cqrs package provides a small toolkit for building CQRS applications on top of EventSourcerer. It generates the boilerplate around commands, command handlers, aggregates and query objects so you can focus on the domain rules.

Installation

composer require eventsourcerer/cqrs

What you get

  • Base Command, CommandHandler and Query contracts.
  • An Aggregate base class with event emission and replay helpers.
  • A command bus that wires handlers via your framework's container.
  • Maker commands to scaffold a new bounded context: command, handler, aggregate, events, query.

Generating a slice

bin/console eventsourcerer:cqrs:make:slice Basket AddItemToBasket
# generates:
#   src/Basket/Command/AddItemToBasket.php
#   src/Basket/Command/AddItemToBasketHandler.php
#   src/Basket/Domain/BasketAggregate.php
#   src/Basket/Domain/Event/ItemAddedToBasket.php
#   src/Basket/Query/GetBasketSummary.php

Handling a command

final class AddItemToBasketHandler implements CommandHandler
{
    public function __construct(private Client $client) {}

    public function __invoke(AddItemToBasket $command): void
    {
        $events  = $this->client->readStream(StreamId::fromString($command->basketId));
        $basket  = BasketAggregate::reconstitute($events);

        $basket->addItemToBasket($command->productId, $command->name, $command->amount);

        $this->client->append($basket->pullNewEvents());
    }
}

Querying the read side

Queries go to projections (see Projections). The CQRS package gives you a thin facade to fetch projection state by id or list, with optional caching, so handlers stay tidy.