PHPackages                             zaw/attribute-driven-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. [Framework](/categories/framework)
4. /
5. zaw/attribute-driven-cqrs

ActiveLibrary[Framework](/categories/framework)

zaw/attribute-driven-cqrs
=========================

A PHP package that simplifies the implementation of the CQRS pattern using attributes, enabling cleaner and more efficient command/query handling.

1.0.1(1y ago)714MITPHP

Since Oct 3Pushed 1y ago1 watchersCompare

[ Source](https://github.com/zawhtetnaing006/attributes-driven-cqrs)[ Packagist](https://packagist.org/packages/zaw/attribute-driven-cqrs)[ RSS](/packages/zaw-attribute-driven-cqrs/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (2)Versions (3)Used By (0)

Attribute Driven CQRS
=====================

[](#attribute-driven-cqrs)

[![PHP Version](https://camo.githubusercontent.com/cc9cdea9aa96b40a822425e981b0a030e3371202973c7d57b74e8e99834f81dc/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253545382e312d626c7565)](https://camo.githubusercontent.com/cc9cdea9aa96b40a822425e981b0a030e3371202973c7d57b74e8e99834f81dc/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253545382e312d626c7565)[![Package List Version](https://camo.githubusercontent.com/ad07c2f82833c50fb2655de89df69b6f0756fdec0500ad2b9177e2a5fc320976/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f76657273696f6e2d76312e302e302d626c7565)](https://camo.githubusercontent.com/ad07c2f82833c50fb2655de89df69b6f0756fdec0500ad2b9177e2a5fc320976/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f76657273696f6e2d76312e302e302d626c7565)

A simple PHP package that makes it easy to implement the CQRS (Command Query Responsibility Segregation) pattern using attributes. With this package, you can streamline command and query handling without a lot of boilerplate, making your code cleaner and more manageable.

Requirement
-----------

[](#requirement)

- PHP 8.1+

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

[](#installation)

```
composer require zaw/attribute-driven-cqrs
```

Examples
--------

[](#examples)

### 1. Commands

[](#1-commands)

- A Command describes a single action. It won't execute it.
- Commands are pure PHP classes whose purpose is to only hold the values needed to execute an operation.
- Commands can be handled by a command handler. Each command must have a handler.
- The `HandleCommandWith` attribute can be used to link a command to its handler. The handler class will receive the command as a parameter in its `handle` method. Note: A command should not return a value. But the package provide a feature to access return values from handlers to `Middlewares` to handle edge cases.

Example:

```
use Zaw\AttributeDrivenCqrs\CommandBus;
use Zaw\AttributeDrivenCqrs\Attributes\HandleCommandWith;

#[HandleCommandWith(CreateUserHandler::class)]
class CreateUserCommand
{
    public function __construct(private string $username, private string $email) {}

    public function getUserName(): string
    {
        return $this->username;
    }

    public function getEmail(): string
    {
        return $this->email;
    }
}

class CreateUserHandler
{
    public function handle(object $command): void
    {
        echo "User '{".$command->getUserName()."}' created with email '{".$command->email."}'";
    }
}

$command = new CreateUserCommand('JohnDoe', 'john@example.com');
CommandBus::getInstance()->handle($command);
```

### 2. Queries

[](#2-queries)

- A query describe a data retrival. But it doens't perform it.
- Each query must have a handler. The `HandleQueryWith` attribute can be used to link a query to its handler.
- The handler class will receive the query as a parameter in its `handle` method.

```
use Zaw\AttributeDrivenCqrs\QueryBus;
use Zaw\AttributeDrivenCqrs\Attributes\HandleQueryWith;

#[HandleQueryWith(GetUserHandler::class)]
class GetUserQuery {
    public function __construct(private int $userId) {}
    public function getUserId()
    {
        return $this->userId;
    }
}

class GetUserHandler {
    public function handle(object $query)
    {
        return $userService->getUser($query->getUserId());
    }
}
$query = new GetUserQuery(1);
$result = QueryBus::getInstance()->handle($query);
```

### 3. Handlers

[](#3-handlers)

Handlers are responsible for executing the logic associated with a command or query.

- Handlers must implement the `handle` method, which accepts the command or query as a parameter. This is where the actual logic related to the action (in the case of commands) or data retrieval (in the case of queries) is performed.
- **Dependency Injection Support**: Handlers can now take advantage of dependency injection. This allows you to inject services, repositories, or other dependencies directly into the handler. The package uses [PHP-DI](https://php-di.org/) to resolve handler dependencies automatically.

Example:

```
use Psr\Log\LoggerInterface;

class CreateUserHandler {
    private LoggerInterface $logger;

    // Services or other dependencies can be injected via the constructor
    public function __construct(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }

    public function handle(CreateUserCommand $command): void
    {
        $this->logger->info("Creating user '{$command->getUserName()}'");
        echo "User '{$command->getUserName()}' created with email '{$command->getEmail()}'";
    }
}
```

```
class GetProductHandler {
    private ProductService $productService;

    // Dependency injection of the ProductService
    public function __construct(ProductService $productService)
    {
        $this->productService = $productService;
    }

    public function handle(GetProductQuery $query): Product
    {
        return $this->productService->getProduct($query->getProductId());
    }
}
```

### 4. Middlewares

[](#4-middlewares)

- Middlewares allow you to execute custom logic before/after a command or query handler is executed.
- Middlewares must implement the `MiddlewareInterface`, which enforces the implementation of the `process` method. The `process` method receives the command or query as the first parameter and the return value from the `handle` method of the CommandHandler/QueryHandler as the second parameter (if applicable).
- **Dependency Injection Support**: Middlewares can now take advantage of dependency injection.

Middlewares can be applied in two ways:

#### Local Middleware

[](#local-middleware)

Local middleware applies to specific commands or queries. You can attach middleware directly using the `BeforeHandle` and `AfterHandle` attributes. Local middleware can be used for purposes such as logging, or dispatching events after a command has been successfully handled.

- **BeforeHandle**: Runs before the handler is executed.
- **AfterHandle**: Runs after the handler has finished.

Example of adding local middleware:

```
use Zaw\AttributeDrivenCqrs\Attributes\BeforeHandle;
use Zaw\AttributeDrivenCqrs\Attributes\AfterHandle;
use Zaw\AttributeDrivenCqrs\Middlewares\Interfaces\MiddlewareInterface;

#[BeforeHandle(LoggingMiddleware::class)]
#[HandleCommandWith(CreateUserHandler::class)]
class CreateUserCommand {
    public function __construct(private string $username, private string $email) {}
}

class LoggingMiddleware implements MiddlewareInterface
{
    public function process($command, $result)
    {
        echo "Logging: Command " . get_class($command) . " is being processed.";
    }
}
```

#### Global Middleware

[](#global-middleware)

Global middleware applies to all commands or queries within a specific bus (CommandBus or QueryBus). These middlewares will automatically run before or after any command or query is handled. Global middleware can be used for purposes such as logging, setting default db connection for each bus, adding authentication for each bus.

To register global middlewares, you can use the `registerBeforeHandle` and `registerAfterHandle` methods:

```
CommandBus::getInstance()->registerBeforeHandle(LoggingMiddleware::class);
CommandBus::getInstance()->registerAfterHandle(ValidationMiddleware::class);
```

Exceptions
----------

[](#exceptions)

The package includes several custom exceptions to help you catch common errors:

- `NoHandlersFoundException`: No handler is found for the command/query.
- `MultipleHandlersFoundException`: Multiple handlers are found for the same command/query.
- `HandlerNotFoundException`: The specified handler class doesn’t exist.
- `InvalidCommandHandlerException`: The handler class doesn’t implement handle method.
- `MiddlewareNotFoundException`: A middleware class couldn’t be found.
- `MiddlewareRegistrationClosedException`: You tried to add global middleware after handling started.

Performance Considerations
--------------------------

[](#performance-considerations)

This package uses PHP reflection to find handlers and middleware. But don’t worry — reflection data is cached, so even with a lot of commands and queries, performance remains smooth(unless we're running thousands of commands and queries within a single request-respones cycle).

License
-------

[](#license)

This package is licensed under the [MIT License](LICENSE).

Contributing
------------

[](#contributing)

We welcome contributions! If you'd like to help improve this package, please open an issue or submit a pull request or contact me directly at . Your feedback is invaluable in making this package better for everyone!

###  Health Score

25

—

LowBetter than 37% of packages

Maintenance36

Infrequent updates — may be unmaintained

Popularity11

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity40

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

Every ~0 days

Total

2

Last Release

588d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/692a1be05fe8b38ebe7b246f6441b6cc78c7adf700a39cd6b8425273e2c425bf?d=identicon)[zaw](/maintainers/zaw)

---

Top Contributors

[![zawhtetnaing006](https://avatars.githubusercontent.com/u/99239794?v=4)](https://github.com/zawhtetnaing006 "zawhtetnaing006 (11 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/zaw-attribute-driven-cqrs/health.svg)

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

###  Alternatives

[slim/slim-skeleton

A Slim Framework skeleton application for rapid development

1.6k458.7k6](/packages/slim-slim-skeleton)[elgg/elgg

Elgg is an award-winning social networking engine, delivering the building blocks that enable businesses, schools, universities and associations to create their own fully-featured social networks and applications.

1.7k15.7k5](/packages/elgg-elgg)[php-di/slim-bridge

PHP-DI integration in Slim

1786.7M98](/packages/php-di-slim-bridge)[php-di/silex-bridge

PHP-DI integration in Silex

2465.4k1](/packages/php-di-silex-bridge)[forme/framework

An MVC framework for WordPress.

175.0k3](/packages/forme-framework)

PHPackages © 2026

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