LaraJS CQRS
Introduction
This package allows the creation and management of multiple command buses, providing a flexible system for handling various commands in your Laravel application. It supports CQRS (Command Query Responsibility Segregation), which separates command and query handling to improve scalability, efficiency, and maintainability.
Quick start
Install
bash
composer require larajs/cqrs:dev-main
Publish config
php
php artisan vendor:publish --tag=larajs-cqrs-config
Structures
txt
.
├── Commands
│ ├── LoginUser
│ │ ├── LoginUserCommand.php
│ │ ├── LoginUserCommandHandler.php
│ │ └── LoginUserController.php
│ └── RegisterUserCommand
│ ├── RegisterUserCommand.php
│ ├── RegisterUserCommandHandler.php
│ └── RegisterUserController.php
├── Queries
│ └── FindUser
│ ├── FindUserController.php
│ ├── FindUserQuery.php
│ └── FindUserQueryHandler.php
└── Resources
└── UserResource.php
Command
Login User
LoginUserController.php
php
<?php
use LaraJS\CQRS\Buses\CommandBusInterface;
class LoginUserController extends Controller
{
public function __construct(private readonly CommandBusInterface $commandBus) {}
public function __invoke(Request $request): UserResource
{
$loginUser = $this->commandBus->handle(new LoginUserCommand($request->get('email'), $request->get('password')));
return UserResource::from($loginUser);
}
}
LoginUserCommand.php
php
<?php
#[Handler(LoginUserCommandHandler::class)]
readonly class LoginUserCommand implements Command
{
public function __construct(public string $email, public string $password) {}
}
LoginUserCommandHandler.php
php
<?php
readonly class LoginUserCommandHandler
{
public function __construct(private UserReadRepositoryInterface $userRepository) {}
public function handle(LoginUserCommand $loginUserCommand): array
{
$user = $this->userRepository->findEmail($loginUserCommand->email);
if (!$user || !Hash::check($loginUserCommand->password, $user->getAttribute('password'))) {
throw ValidationException::withMessages([
'email' => ['The provided credentials are incorrect.'],
]);
}
return $user;
}
}
Register User
RegisterUserController.php
php
<?php
use LaraJS\CQRS\Buses\CommandBusInterface;
use LaraJS\CQRS\IdResource;
class RegisterUserController extends Controller
{
public function __construct(private readonly CommandBusInterface $commandBus) {}
public function __invoke(Request $request): IdResource
{
$loginUser = $this->commandBus->handle(new RegisterUserCommand($request->get('email'), $request->get('password'), $request->get('role')));
return IdResource::from($loginUser); // return only ID
}
}
RegisterUserCommand.php
php
<?php
use LaraJS\CQRS\Attributes\Handler;
use LaraJS\CQRS\Contracts\Command;
// By default will auto add suffix Handler
readonly class RegisterUserCommand implements Command
{
public function __construct(public string $email, public string $password, public string $role) {}
}
RegisterUserCommandHandler.php
php
<?php
readonly class RegisterUserCommandHandler
{
public function __construct(private UserWriteRepositoryInterface $userRepository) {}
public function handle(LoginUserCommand $loginUserCommand): array
{
$user = $this->userRepository->create($loginUserCommand->email, $loginUserCommand->password, $loginUserCommand->role);
return $user;
}
}
Query
Find User
FindUserController.php
php
<?php
use LaraJS\CQRS\Buses\QueryBusInterface;
class FindUserController extends Controller
{
public function __construct(private readonly QueryBusInterface $queryBus)
{
}
public function __invoke(int $id): UserResource
{
$user = $this->queryBus->handle(new FindUserQuery($id));
return UserResource::from($user);
}
}
FindUserQuery.php
php
<?php
use LaraJS\CQRS\Attributes\Handler;
use LaraJS\CQRS\Contracts\Command;
#[Handler(FindUserQueryHandler::class)]
readonly class FindUserQuery implements Command
{
public function __construct(public int $id)
{
}
}
FindUserQuery.php
php
<?php
class FindUserQueryHandler
{
public function __construct(private UserReadRepositoryInterface $userRepository) {}
public function handle(FindUserQuery $query): User
{
return $this->userRepository->find($query->id);
}
}
Registering middleware
php
// This will prepend ValidationMiddleware to the existing middleware
#[Middleware([ValidationMiddleware::class], true)]
class RegisterUserCommandHandler
{
public function handle(RegisterUserCommand $command): int
{
return $user->id;
}
}
php
#[ResetMiddleware]
#[Middleware([ValidationMiddleware::class])]
class RegisterUserCommandHandler
{
public function handle(RegisterUserCommand $command): int
{
return $user->id;
}
}
cqrs.php
php
'buses' => [
'command' => [
'class' => CommandBus::class,
'interface' => CommandBusInterface::class,
'alias' => 'bus.command',
'middleware' => [
// default middleware
],
'handler_resolver' => SuffixHandlerResolver::class,
'handler_method' => 'handle',
],
'query' => [
'class' => QueryBus::class,
'interface' => QueryBusInterface::class,
'alias' => 'bus.query',
'middleware' => [
// default middleware
],
'handler_resolver' => SuffixHandlerResolver::class,
'handler_method' => 'handle',
],
],