Lightweight message bus supporting CQRS for Spiral Framework

Maintainers

👁 butschster

Package info

github.com/spiral-packages/cqrs

pkg:composer/spiral-packages/cqrs

Statistics

Installs: 19 752

Dependents: 0

Suggesters: 0

Stars: 9

Open Issues: 3

v2.3.0 2023-11-30 08:33 UTC

Requires (Dev)

Suggests

None

Provides

None

Conflicts

None

Replaces

None

MIT 8782a5baaffd8e88316e40738273a018d50f94cc

  • butschster <butschster.woop@gmail.com>

cqrscommand-busspiralquery-busspiral-packages

This package is auto-updated.

Last update: 2026-06-20 14:30:41 UTC


README

👁 PHP
👁 Latest Version on Packagist
👁 Total Downloads
👁 run-tests

It's a lightweight messaging facade. It allows you to define the API of your model with the help of messages.

  • Command messages describe actions your model can handle.
  • Query messages describe available information that can be fetched from your (read) model.

Requirements

Make sure that your server is configured with following PHP version and extensions:

  • PHP 8.1+
  • Spiral framework 3.0+

Installation

You can install the package via composer:

composer require spiral-packages/cqrs

After package install you need to register bootloader from the package.

protected const LOAD = [
 // ...
 \Spiral\Cqrs\Bootloader\CqrsBootloader::class,
];

Note: if you are using spiral-packages/discoverer, you don't need to register bootloader by yourself.

Usage

You can also register command and query handlers via attributes

Commands

Command definition

class StoreUser implements \Spiral\Cqrs\CommandInterface
{
 public function __construct(
 public Uuid $uuid,
 public string $username,
 public string $password,
 public \DateTimeImmutable $registeredAt,
 ) {
 }
}

Command handler definition

To register command handler you just need to add attribute on method that should be invoked.

class StoreUserHandler
{
 public function __construct(
 private EntityManagerInterface $entityManager
 ) {

 }

 #[\Spiral\Cqrs\Attribute\CommandHandler]
 public function __invoke(StoreUser $command)
 {
 $this->entityManager->persist(
 new User(
 $command->uuid,
 $command->username,
 $command->password,
 $command->registeredAt
 )
 );

 $this->entityManager->run();
 }
}

Dispatch command

use Ramsey\Uuid\Uuid;

class UserController
{
 public function store(UserStoreRequest $request, \Spiral\Cqrs\CommandBusInterface $bus)
 {
 $bus->dispatch(new StoreUser(
 $uuid = Uuid::uuid4(),
 $request->getUsername(),
 $request->getPassword(),
 new \DateTimeImmutable()
 ));

 return $uuid;
 }
}

Queries

Query definition

class FindAllUsers implements \Spiral\Cqrs\QueryInterface
{
 public function __construct(
 public array $roles = []
 ) {
 }
}
class FindUserById implements \Spiral\Cqrs\QueryInterface
{
 public function __construct(
 public Uuid $uuid
 ) {
 }
}

Query handler definition

class UsersQueries
{
 public function __construct(
 private UserRepository $users
 ) {
 }

 #[\Spiral\Cqrs\Attribute\QueryHandler]
 public function findAll(FindAllUsers $query): UserCollection
 {
 $scope = [];
 if ($query->roles !== []) {
 $scope['roles'] = $query->roles
 }

 return new UserCollection(
 $this->users->findAll($scope)
 );
 }

 #[\Spiral\Cqrs\Attribute\QueryHandler]
 public function findById(FindUserById $query): UserResource
 {
 return new UserResource(
 $this->users->findByPK($query->uuid)
 );
 }
}

Dispatch queries

use Ramsey\Uuid\Uuid;

class UserController
{
 public function index(UserFilters $filters, \Spiral\Cqrs\QueryBusInterface $bus)
 {
 return $bus->ask(
 new FindAllUsers($filters->roles())
 )->toArray();
 }

 public function show(string $uuid, \Spiral\Cqrs\QueryBusInterface $bus)
 {
 return $bus->ask(
 new FindUserById(Uuid::fromString($uuid))
 )->toArray();
 }
}

Testing

composer test

License

The MIT License (MIT). Please see License File for more information.