Skip to content

Commit

Permalink
make all commands reconstitutable
Browse files Browse the repository at this point in the history
  • Loading branch information
juliangut committed Sep 24, 2018
1 parent a14ad61 commit d9a9532
Show file tree
Hide file tree
Showing 9 changed files with 86 additions and 150 deletions.
70 changes: 61 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,29 +38,81 @@ Commands are DTOs that carry all the information for an action to happen on Writ

You can create your own by implementing `Gears\CQRS\Command` or extend from `Gears\CQRS\AbstractCommand` which ensures command immutability and payload is composed only of scalar values. AbstractCommand has a protected constructor forcing you to create a custom static constructor

```php
use Gears\CQRS\AbstractCommand;

class CreateUserCommand extends AbstractCommand
{
public static function instance(
string $name,
string lastname,
\DateTimeImmutable $birthDate
): self {
return new self([
'name' => $name,
'lastname' => $lastname,
'birthDate' => $birthDate->format('U'),
]);
}
}
```

#### Async

Having command assuring all of its payload is composed only of scalar values proves handy when you want to delegate command handling to a queue system, serializing/deserializing scalar values is trivial in any format and language

Asynchronous behaviour must be implemented at CommandBus level, command bus must be able to identify async commands (a map of commands, implementing an interface, by a payload parameter, ...) and enqueue them

_Asynchronous behaviour is out of the scope of this package, this is the whole process of enqueue, dequeue, command serialization and reconstitution, ..._

### Queries

Queries are DTOs that carry all the information for a request to be made on Read Model

You can create your own by implementing `Gears\CQRS\Query` or extend from `Gears\CQRS\AbstractQuery` which ensures query immutability and payload is composed only of scalar values. AbstractQuery has a protected constructor forcing you to create a custom static constructor

### Async commands

There is a special `Gears\CQRS\AsyncCommand` and corresponding `Gears\CQRS\AbstractAsyncCommand` which are meant to be used when commands are needed to be sent to queue systems so their handling is delegated asynchronously

This is the case where having command assuring all its payload is composed only of scalar values proves handy, serializing and unserializing scalar values is trivial in any format and language

Have a look at [phpgears/dto](https://github.com/phpgears/dto) fo a better understanding of how commands and queries hold their payload
```php
use Gears\CQRS\AbstractQuery;

_Asynchronous behaviour must be implemented at CommandBus level and is out of the scope of this package, this is enqueue, dequeue, command serialization and reconstitution, ..._
class FindUserQuery extends AbstractQuery
{
public static function instance(string $name): self
{
return new self(['name' => $name]);
}
}
```

### Handlers

Commands and Queries are handed over to `Gears\CQRS\CommandHandler` and `Gears\CQRS\QueryHandler` respectively on their corresponding buses

`AbstractCommandHandler` and `AbstractQueryHandler` are provided, this abstract classes verifies the type of the command/query so you can focus only on implementing the handling logic

Be aware that QueryHandler::handle method must return a DTO object from [phpgears/dto](https://github.com/phpgears/dto)
```php
class CreateUserCommandHandler extends AbstractCommandHandler
{
protected function getSupportedCommandType(): string
{
return CreateUserCommand::class;
}

protected function handleCommand(Command $command): void
{
/* @var CreateUserCommand $command */

$user = new User(
$command->getName(),
$command->getLastname(),
$command->getBirthDate()
);

[...]
}
}
```

Have a look at [phpgears/dto](https://github.com/phpgears/dto) fo a better understanding of how commands and queries are built and how they hold payload

### Buses

Expand Down
3 changes: 1 addition & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@
"name": "phpgears/cqrs",
"description": "CQRS base",
"keywords": [
"immutable",
"CQRS",
"immutable",
"command",
"asynchronous command",
"query"
],
"homepage": "https://github.com/phpgears/cqrs",
Expand Down
57 changes: 0 additions & 57 deletions src/AbstractAsyncCommand.php

This file was deleted.

8 changes: 8 additions & 0 deletions src/AbstractCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ final protected function __construct(array $parameters)
$this->setPayload($parameters);
}

/**
* {@inheritdoc}
*/
final public static function reconstitute(array $parameters)
{
return new static($parameters);
}

/**
* {@inheritdoc}
*
Expand Down
29 changes: 0 additions & 29 deletions src/AsyncCommand.php

This file was deleted.

9 changes: 9 additions & 0 deletions src/Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,13 @@ public function get(string $parameter);
* @return array<string, mixed>
*/
public function getPayload(): array;

/**
* Reconstitute command.
*
* @param mixed[] $parameters
*
* @return mixed|self
*/
public static function reconstitute(array $parameters);
}
30 changes: 0 additions & 30 deletions tests/CQRS/AbstractAsyncCommandTest.php

This file was deleted.

7 changes: 7 additions & 0 deletions tests/CQRS/AbstractCommandHandlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,11 @@ public function testInvalidCommandType(): void
$handler = new AbstractCommandHandlerStub();
$handler->handle($command);
}

public function testReconstitute(): void
{
$command = AbstractCommandStub::reconstitute(['parameter' => 'one']);

$this->assertTrue($command->has('parameter'));
}
}
23 changes: 0 additions & 23 deletions tests/CQRS/Stub/AbstractAsyncCommandStub.php

This file was deleted.

0 comments on commit d9a9532

Please sign in to comment.