gian-tiaga / spiral-cqrs
CQRS bus package for Spiral applications
Requires
- php: >=8.5
- cycle/database: ^2.16
- php-http/discovery: ^1.20
- psr/log: ^3.0
- spiral/framework: ^3.16
Requires (Dev)
- gian-tiaga/phpstan-strict-rules: ^0.1.0
- php-cs-fixer/shim: ^3.95.23
- phpstan/phpstan: ^2.1.54
- phpunit/phpunit: ^13.1
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
gian-tiaga/spiral-cqrs добавляет в Spiral-приложение простые шины команд и запросов.
Пакет даёт:
CommandBusInterfaceдля сценариев, которые меняют состояние;QueryBusInterfaceдля сценариев чтения;- атрибут
#[Transactional]для транзакций команд; - атрибут
#[LogOperation]для debug-логов выполнения; - PHPStan-правило, которое требует передавать handler как
$handler->handle(...).
Установка
composer require gian-tiaga/spiral-cqrs:^0.1.0
Подключите bootloader в приложении:
use GianTiaga\SpiralCqrs\Bootloader\CqrsBootloader; protected const LOAD = [ CqrsBootloader::class, ];
Bootloader регистрирует CommandBusInterface и QueryBusInterface.
Command
Command — это объект с входными данными сценария. Handler выполняет сценарий.
use GianTiaga\SpiralCqrs\CommandBusInterface; use GianTiaga\SpiralCqrs\Attribute\LogOperation; use GianTiaga\SpiralCqrs\Attribute\Transactional; final readonly class CreatePostCommand { public function __construct( public string $authorId, public string $title, public string $body, ) {} } final readonly class CreatePostHandler { public function __construct( private PostRepository $postRepository, ) {} #[Transactional] #[LogOperation(name: 'post.create')] public function handle(CreatePostCommand $command): string { $post = Post::create( authorId: $command->authorId, title: $command->title, body: $command->body, ); $this->postRepository->add($post); return $post->id(); } } $postId = $commandBus->dispatch( command: new CreatePostCommand( authorId: $authorId, title: $title, body: $body, ), handler: $createPostHandler->handle(...), );
#[Transactional] работает только для command handler. Если поставить его на query handler, package PHPStan-правило сообщит об ошибке.
Query
Query читает данные и не должен менять состояние приложения.
use GianTiaga\SpiralCqrs\QueryBusInterface; final readonly class GetPostQuery { public function __construct( public string $postId, ) {} } final readonly class GetPostHandler { public function __construct( private PostReadRepository $postReadRepository, ) {} public function handle(GetPostQuery $query): PostView { return $this->postReadRepository->getView($query->postId); } } $post = $queryBus->dispatch( query: new GetPostQuery(postId: $postId), handler: $getPostHandler->handle(...), );
Логи и исключения
#[LogOperation] пишет debug-лог перед запуском handler и после завершения. Сообщения логов и служебные исключения пакета написаны на русском языке.
PHPStan
Чтобы проверять вызовы dispatch(), подключите extension:
includes: - vendor/gian-tiaga/spiral-cqrs/extension.neon
Разрешено:
$commandBus->dispatch( command: $command, handler: $handler->handle(...), );
Запрещено:
$commandBus->dispatch(command: $command, handler: fn() => null); $commandBus->dispatch(command: $command, handler: [$handler, 'handle']); $commandBus->dispatch(command: $command, handler: $handler);
Идентификаторы ошибок:
gianTiaga.spiralCqrs.handlerCallableRequired;gianTiaga.spiralCqrs.transactionalQueryHandler.
Локальная разработка
Чтобы править пакет рядом с приложением, подключите его каталог path repository — путь считается от корня приложения:
{
"repositories": [
{
"type": "path",
"url": "../spiral-cqrs",
"options": {
"symlink": true
}
}
]
}
Проверки пакета:
composer install
composer test
composer phpstan