CQRS code example "Requested"
Tags: cqrs, php, codeexample, architecture
Published: 2020-11-30 14:17:24


This post is linked with the detailed article [Real-life DDD in an "onionshell"](https://dev.to/soulwife/real-life-ddd-in-an-onionshell-3ohb) and explains with code examples specific version of a standard CQRS command requests. This customization allows us to handle different types of command requests integrating with bounded contexts. 

Our service has two types of API requests: external "usecase" type and "command request" type, that can be external and internal. The second type can be managed differently, depending on it’s goal. It can be a simple external request to handle a command. Another time it can be a complex task with transaction in it. So we should use a different approach for every version of the task according to the configuration pre-set. Either way we create a task request and manage it using a message broker. 
 
We have "usecase" and "request-commands" concept. Last one should be used for any server-to-server or context-to-context interaction. 
Request command should be created via CommandRunner (RequestCommandHandlerService), that operates with command handlers and have the following interface:
```
/**
 * Interface CommandRunner
 * @package Utility\RequestCommand
 */
interface CommandRunner
{
    /**
     * @param TaskRequestInterface $taskRequest
     * @throws JsonException
     */
    public function send(TaskRequestInterface $taskRequest): void;

    /**
     * @param TaskRequestInterface $taskRequest
     * @throws CommandRequestException
     */
    public function run(TaskRequestInterface $taskRequest): void;
}
```
All of handle pairs should be determined in configuration `config.php/requestCommand.php`. For example,

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/0w0aobah86o82cf69c4t.png)

If request command is going to be called externally you are going to need alias for this call:
```
/*
|------------------------------------------------------------
| Handlers Aliases
|------------------------------------------------------------
*/
'requestAliases' => [
    'makeMessage' => MakeMessageTaskRequest::class,
    'createTeam'  => CreateTeamTaskRequest::class,
],
```

That's way we can add multi-purpose Handler-Request pair to 'requestCommand'. It can be simple peer-to-peer:

`AddScenarioStatisticTaskRequest::class => AddScenarioStatisticHandler::class`

Or transaction mode (all handlers are going to be committed in one transaction):

```
MakeMessageTaskRequest::class => [
     MakeMessageTaskRequest::class => MakeMessageHandler::class,
     UpdateSessionLastSeenTaskRequest::class => UpdateSessionLastSeenHandler::class
],
```

Pay attention here: you should create only one request via command handler, for example 'MakeMessageTaskRequest' and all other requests are going to be created automatically according with your chain of requests/handlers. 

After that you can create specific TaskRequest with entity-specific DTO in Infrastructure/TaskRequest and Handler for it in Application/CommandHandler. 
TaskRequest example:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/9tpbksnktt2qipyn7zdt.png)

Yep, it's going to be DeactivateUserTariffPlanDTO instead of RequestDTO immediately after we update PHP version to 8.0 :)

CommandHandler example (it can be in any context):

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/cmnvi68y97tillo89hex.png)

As you can see, handler 'process' method should call Application Service accordingly with procedure, that you need. Add Middleware Validators for each of them accordingly in Handler.

Handler without Transactions should implement `RequestCommandHandler` interface and Transaction Handlers should implement `RequestCommandHandler,TransactionRequestCommandHandler` interfaces.

There are two types of transaction handlers: "insiders" and "closing". Insiders (implements `InsiderTransactionRequestCommandHandler` interface as well) should create DTO for the next transaction request in the `process()` method via creating  
`$this->nextTransactionRequestDTO` and return it in the following way:

```
/**
 * @return bool
 */
public function isInTransaction(): bool
{
    return true;
}

/**
 * @return RequestDTO|null
*/
public function getNextTransactionRequestDTO(): RequestDTO
{
    return $this->nextTransactionRequestDTO;
} 
```

Closing one closes transaction (the last request on the list), so it should only implement `isInTransaction` method:
```
/**
 * @return bool
*/
public function isInTransaction(): bool
{
    return false;
}
```

I am planning to create two different strategies for "insiders" and "closing" request, but it haven't done yet.
`TaskHandler` is going to handle all inner processes, such as setup transactions decorator service with UnitOfWork, obtain and handle request-commands pairs and request data from the configuration service, handle low-level exceptions and so on.

 ![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/1kvupvq2ue0h3s8smkk8.png)

All we have left to do is to start listen "request-command" queue via message broker (we use RabbitMQ, but it's going to work with any of brokers, anyway). 

***Example for DeactivateUserTariffPlan:***

From any of bounded contexts services inside API:

```
$this->commandRunner->send(new DeactivateUserTariffPlanTaskRequest(new DeactivateUserTariffPlanDTO(['userId' => 1])));
```

From external services (for example, API Gateway):

Send json data to the "request-command" queue:
```
[
    'userId' => 1
]
```