Skip to content
markdown
---
name: packages-larajs-cqrs
description: Use when the user asks about the LaraJS CQRS package, Command Query Responsibility Segregation pattern in Laravel, installing larajs/cqrs, publishing the cqrs config, creating command handlers (Command, CommandHandler, CommandBusInterface), creating query handlers (Query, QueryHandler, QueryBusInterface), CQRS folder structure (Commands/, Queries/, Resources/), the #[Handler] attribute for handler resolution, #[Middleware] and #[ResetMiddleware] attributes for registering middleware on handlers, or configuring cqrs.php buses (command bus, query bus, SuffixHandlerResolver).
---

# 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)
    {
    }
}
```

**FindUserQueryHandler.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

Prepend middleware to an existing middleware stack:

```php
// This will prepend ValidationMiddleware to the existing middleware
#[Middleware([ValidationMiddleware::class], true)]
class RegisterUserCommandHandler
{
    public function handle(RegisterUserCommand $command): int
    {
        return $user->id;
    }
}
```

Reset middleware and add new ones:

```php
#[ResetMiddleware]
#[Middleware([ValidationMiddleware::class])]
class RegisterUserCommandHandler
{
    public function handle(RegisterUserCommand $command): int
    {
        return $user->id;
    }
}
```

## Configuration (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',
    ],
],
```