PHPackages                             componenta/cqrs - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. componenta/cqrs

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

componenta/cqrs
===============

CQRS (Command Query Responsibility Segregation) library for PHP 8.4+

v1.0.0(1mo ago)058MITPHPPHP &gt;=8.4

Since Jun 21Pushed 1mo agoCompare

[ Source](https://github.com/componenta/cqrs)[ Packagist](https://packagist.org/packages/componenta/cqrs)[ RSS](/packages/componenta-cqrs/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (1)Dependencies (10)Versions (2)Used By (8)

Componenta CQRS
===============

[](#componenta-cqrs)

`componenta/cqrs` is the core CQRS runtime for PHP 8.4+. It provides command and query buses, handler locators, command operation objects, command events, and command/query discovery attributes used by application-level tooling.

The package intentionally contains only the neutral runtime. Middleware that requires policy, locks, queues, database transactions, or console integration lives in separate packages.

Installation
------------

[](#installation)

```
composer require componenta/cqrs
```

Dependencies
------------

[](#dependencies)

DependencyPurposePHP `>=8.4`Modern language features and strict types.`componenta/arrayable`Shared array conversion contract.`componenta/config`Config provider integration.`componenta/di`Handler/listener invocation through `CallableInvokerInterface`.`componenta/iterator`Iterator helpers for locators.`componenta/reflection`Metadata helpers for command attributes.`psr/container`Service lookup.`ramsey/uuid`Operation identifiers.Optional Packages
-----------------

[](#optional-packages)

PackageAdds`componenta/cqrs-policy`Command and query policy middleware. Use `#[Allow]` from `componenta/policy` for public flows; do not use skip-policy flags as a public-access model.`componenta/cqrs-retry`Command retry middleware for commands marked with `#[Retry]`.`componenta/cqrs-lock`Symfony Lock command middleware for commands marked with `#[Lock]`.`componenta/cqrs-transaction-cycle`Cycle Database transaction middleware.`componenta/cqrs-transport`Transport contracts, serializer, async middleware, and command worker.`componenta/cqrs-transport-cycle`Cycle Database transport implementation.`componenta/cqrs-transport-console`Symfony Console worker command.`componenta/cqrs-app`Attribute discovery and build-time map compilers.Quick Start
-----------

[](#quick-start)

```
use Componenta\CQRS\Command\CommandBusInterface;
use Componenta\CQRS\ConfigKey;

final readonly class CalculateTotalCommand
{
    public function __construct(
        public int $price,
        public int $quantity,
    ) {}
}

final readonly class CalculateTotalHandler
{
    public function __invoke(CalculateTotalCommand $command): int
    {
        return $command->price * $command->quantity;
    }
}

return [
    new Componenta\CQRS\ConfigProvider(),

    ConfigKey::COMMAND_HANDLER_MAP => [
        CalculateTotalCommand::class => [CalculateTotalHandler::class, '__invoke'],
    ],
];

/** @var CommandBusInterface $commands */
$commands = $container->get(CommandBusInterface::class);
$operation = $commands->dispatch(new CalculateTotalCommand(price: 50, quantity: 3));

$result = $operation->result?->value; // 150
```

Configuration
-------------

[](#configuration)

Register the runtime provider:

```
return [
    new Componenta\CQRS\ConfigProvider(),
];
```

The provider registers:

ServicePurpose`CommandBusInterface`Dispatches commands through the configured command middleware chain.`QueryBusInterface`Handles queries through the configured query middleware chain.`CommandHandlerLocatorInterface`Reads `ConfigKey::COMMAND_HANDLER_MAP`.`CommandListenersLocatorInterface`Reads `ConfigKey::COMMAND_LISTENER_MAP`.`QueryHandlerLocatorInterface`Reads `ConfigKey::QUERY_HANDLER_MAP`.`CommandAttributeProviderInterface`Reads `#[Async]`, `#[Retry]`, and `#[Lock]` from compiled maps or reflection.Important keys:

KeyValue`ConfigKey::COMMAND_MIDDLEWARES`Command middleware list in execution order.`ConfigKey::QUERY_MIDDLEWARES`Query middleware list in execution order.`ConfigKey::COMMAND_HANDLER_MAP``Command::class =&gt; callable`ConfigKey::COMMAND_LISTENER_MAP`Command event listener map.`ConfigKey::QUERY_HANDLER_MAP``Query::class =&gt; callable`ConfigKey::COMMAND_ATTRIBUTE_MAP`Compiled metadata for `#[Async]`, `#[Retry]`, and `#[Lock]`.`ConfigKey::COMPILED_MAPS`Enables compiled maps.`Componenta\CQRS\ConfigProvider` registers empty command and query middleware lists by default. Add optional middleware from the packages listed above when the application needs authorization, retries, locks, transactions, async execution, or workers.

Commands
--------

[](#commands)

A command is an object with data for a state-changing use case. `CommandBusInterface::dispatch(object $command, array $attributes = [])` returns an immutable `OperationInterface` with operation id, attributes, and a result when the command runs synchronously.

Handlers are resolved through `CommandHandlerLocatorInterface`. A handler map entry can be a callable or a `[class-string, method-string]` pair. Class/method pairs are resolved lazily through the container.

`#[AsCommandHandler(?string $command = null)]` is discovery metadata for `componenta/cqrs-app`. If the command is omitted, `cqrs-app` infers it from the handler parameter.

Command Middleware
------------------

[](#command-middleware)

Command middleware implements:

```
public function execute(OperationInterface $operation, OperationHandlerInterface $handler): OperationInterface;
```

Core middleware:

MiddlewareResponsibility`SequentialMiddleware`Runs nested dispatches after the root command.`EventMiddleware`Emits command lifecycle events.`HandleCommandHandler`Terminal handler that locates and invokes the command handler. The bus factory wires it separately.Order is behavior. Keep cross-cutting concerns in middleware instead of hiding them in handlers.

Command Attributes
------------------

[](#command-attributes)

AttributeTargetConstructorBehavior`#[AsCommandHandler]`class or method`?string $command = null`Discovery metadata for command handlers.`#[AsCommandListener]`class`string $command, int $priority = 0, array $eventTypes = []`Discovery metadata for command event listeners.`#[Async]`command class`string $transport = 'default', int $delay = 0`Metadata consumed by `componenta/cqrs-transport`.`#[Retry]`command class`int $attempts = 3, int $delayMs = 100, float $multiplier = 1.0, int $maxDelayMs = 10000`Metadata consumed by `componenta/cqrs-retry`.`#[Lock]`command class`string $key, float $ttl = 300.0, bool $blocking = true`Metadata consumed by `componenta/cqrs-lock`.Command Events
--------------

[](#command-events)

EventWhen`CommandProcessEvent`Before command execution.`CommandProcessedEvent`After successful execution.`CommandFailedEvent`After failure, before the exception is rethrown.Listeners are resolved through `CommandListenersLocatorInterface`. `EventMiddleware` suppresses listener failures by default. Use `suppressExceptions: false` for fail-fast development behavior.

Queries
-------

[](#queries)

Queries describe read use cases and return the handler result directly:

```
use Componenta\CQRS\Query\QueryBusInterface;

$post = $queries->handle(new GetPostQuery($id));
```

`QueryBusInterface::handle(object $query, ContextInterface|array $context = [])` converts arrays to immutable `Context` before middleware receives them.

Handlers are resolved through `QueryHandlerLocatorInterface`. `#[AsQueryHandler(?string $query = null)]` is discovery metadata used by `componenta/cqrs-app`.

Extension Points
----------------

[](#extension-points)

ReplaceContractWhen to useCommand name`NamedCommandInterface` or `CommandNameResolverInterface`The handler-map key must differ from the command class FQCN.Query name`NamedQueryInterface` or `QueryNameResolverInterface`The handler-map key must differ from the query class FQCN.Command chain step`Componenta\CQRS\Command\Middleware\MiddlewareInterface`A custom step must run around command execution.Query chain step`Componenta\CQRS\Query\Middleware\MiddlewareInterface`A custom step must run around query execution.Command event listeners`CommandListenerInterface`A side effect should react to command events without changing the command handler.Command metadata`CommandAttributeProviderInterface``#[Async]`, `#[Retry]`, and `#[Lock]` must come from a source other than reflection or the standard compiled map.Failures
--------

[](#failures)

FailureExceptionMissing command handler`Componenta\CQRS\Command\Exception\HandlerNotFoundException`Invalid command handler`Componenta\CQRS\Command\Exception\InvalidHandlerException`Missing query handler`Componenta\CQRS\Query\Exception\HandlerNotFoundException`

###  Health Score

42

—

FairBetter than 88% of packages

Maintenance92

Actively maintained with recent releases

Popularity5

Limited adoption so far

Community13

Small or concentrated contributor base

Maturity51

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

39d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/20490712?v=4)[Andrey Shelamkoff](/maintainers/Shelamkoff)[@Shelamkoff](https://github.com/Shelamkoff)

---

Top Contributors

[![Shelamkoff](https://avatars.githubusercontent.com/u/20490712?v=4)](https://github.com/Shelamkoff "Shelamkoff (1 commits)")

---

Tags

querycommanddddbuscqrs

###  Code Quality

TestsPest

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/componenta-cqrs/health.svg)

```
[![Health](https://phpackages.com/badges/componenta-cqrs/health.svg)](https://phpackages.com/packages/componenta-cqrs)
```

###  Alternatives

[laravel/framework

The Laravel Framework.

34.8k543.8M20.6k](/packages/laravel-framework)[ecotone/ecotone

Enterprise architecture layer for Laravel and Symfony — CQRS, Event Sourcing, Durable Workflows (Sagas, Orchestrators), Projections, and Outbox messaging via PHP attributes.

564576.7k54](/packages/ecotone-ecotone)[patchlevel/event-sourcing

A lightweight but also all-inclusive event sourcing library with a focus on developer experience

211362.9k13](/packages/patchlevel-event-sourcing)[oat-sa/generis

TAO generis library

10148.8k125](/packages/oat-sa-generis)[pauci/cqrs

CQRS library

1725.2k3](/packages/pauci-cqrs)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
