-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #483 from patchlevel/update-docs
improve aggregate, clock, event bus and message decorator docs
- Loading branch information
Showing
9 changed files
with
263 additions
and
140 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,135 +1,171 @@ | ||
# UUID | ||
# Aggregate ID | ||
|
||
A UUID can be generated for the `aggregateId`. There are two popular libraries that can be used: | ||
The `aggregate id` is a unique identifier for an aggregate. | ||
It is used to identify the aggregate in the event store. | ||
The `aggregate` does not care how the id is generated, | ||
since only an aggregate-wide unique string is expected in the store. | ||
|
||
* [ramsey/uuid](https://github.com/ramsey/uuid) | ||
* [symfony/uid](https://symfony.com/doc/current/components/uid.html) | ||
This library provides you with a few options for generating the id. | ||
|
||
The `aggregate` does not care how the id is generated, since only an aggregate-wide unique string is expected here. | ||
## Uuid | ||
|
||
The easiest way is to use an `uuid` as an aggregate ID. | ||
For this, we have the `Uuid` class, which is a simple wrapper for the [ramsey/uuid](https://github.com/ramsey/uuid) library. | ||
|
||
You can use it like this: | ||
|
||
```php | ||
use Patchlevel\EventSourcing\Aggregate\BasicAggregateRoot; | ||
use Patchlevel\EventSourcing\Aggregate\Uuid; | ||
use Patchlevel\EventSourcing\Attribute\Aggregate; | ||
use Patchlevel\EventSourcing\Attribute\Apply; | ||
use Ramsey\Uuid\Uuid; | ||
use Ramsey\Uuid\UuidInterface; | ||
use Patchlevel\EventSourcing\Attribute\Id; | ||
use Patchlevel\EventSourcing\Serializer\Normalizer\IdNormalizer; | ||
|
||
#[Aggregate('profile')] | ||
final class Profile extends BasicAggregateRoot | ||
{ | ||
private UuidInterface $id; | ||
private string $name; | ||
#[Id] | ||
#[IdNormalizer(Uuid::class)] | ||
private Uuid $id; | ||
} | ||
``` | ||
|
||
public function aggregateRootId(): string | ||
{ | ||
return $this->id->toString(); | ||
} | ||
|
||
public function id(): UuidInterface | ||
{ | ||
return $this->id; | ||
} | ||
|
||
public function name(): string | ||
{ | ||
return $this->name; | ||
} | ||
!!! note | ||
|
||
public static function create(string $name): self | ||
{ | ||
$id = Uuid::uuid4(); | ||
|
||
$self = new self(); | ||
$self->recordThat(new ProfileCreated($id, $name)); | ||
If you want to use snapshots, then you have to make sure that the aggregate id are normalized. | ||
You can find how to do this [here](normalizer.md). | ||
|
||
return $self; | ||
} | ||
|
||
#[Apply] | ||
protected function applyProfileCreated(ProfileCreated $event): void | ||
{ | ||
$this->id = $event->profileId(); | ||
$this->name = $event->name(); | ||
} | ||
You have multiple options for generating an uuid: | ||
|
||
```php | ||
use Patchlevel\EventSourcing\Aggregate\Uuid; | ||
|
||
$uuid = Uuid::v6(); | ||
$uuid = Uuid::v7(); | ||
$uuid = Uuid::fromString('d6e8d7a0-4b0b-4e6a-8a9a-3a0b2d9d0e4e'); | ||
``` | ||
|
||
!!! Note | ||
|
||
We offer you the uuid versions 6 and 7, because they are the most suitable for event sourcing. | ||
More information about uuid versions can be found [here](https://uuid.ramsey.dev/en/stable/rfc4122.html). | ||
|
||
## Custom ID | ||
|
||
If you don't want to use an uuid, you can also use the custom ID implementation. | ||
This is a value object that holds any string. | ||
|
||
```php | ||
use Patchlevel\EventSourcing\Aggregate\BasicAggregateRoot; | ||
use Patchlevel\EventSourcing\Aggregate\CustomId; | ||
use Patchlevel\EventSourcing\Attribute\Aggregate; | ||
use Patchlevel\EventSourcing\Attribute\Apply; | ||
use Patchlevel\EventSourcing\Attribute\Id; | ||
use Patchlevel\EventSourcing\Serializer\Normalizer\IdNormalizer; | ||
|
||
#[Aggregate('profile')] | ||
final class Profile extends BasicAggregateRoot | ||
{ | ||
#[Id] | ||
#[IdNormalizer(CustomId::class)] | ||
private CustomId $id; | ||
} | ||
``` | ||
|
||
Or even better, you create your own aggregate-specific id class. | ||
!!! note | ||
|
||
If you want to use snapshots, then you have to make sure that the aggregate id are normalized. | ||
You can find how to do this [here](normalizer.md). | ||
|
||
So you can use any string as an id: | ||
|
||
```php | ||
use Patchlevel\EventSourcing\Aggregate\CustomId; | ||
|
||
$id = CustomId::fromString('my-id'); | ||
``` | ||
|
||
## Implement own ID | ||
|
||
Or even better, you create your own aggregate-specific ID class. | ||
This allows you to ensure that the correct id is always used. | ||
The whole thing looks like this: | ||
|
||
```php | ||
use Ramsey\Uuid\Uuid; | ||
use Patchlevel\EventSourcing\Aggregate\AggregateRootId; | ||
|
||
class ProfileId | ||
class ProfileId implements AggregateRootId | ||
{ | ||
private string $id; | ||
|
||
public function __construct(string $id) | ||
{ | ||
$this->id = $id; | ||
} | ||
|
||
public static function generate(): self | ||
{ | ||
return new self(Uuid::uuid4()->toString()); | ||
private function __construct( | ||
private readonly string $id | ||
){ | ||
} | ||
|
||
public function toString(): string | ||
{ | ||
return $this->id; | ||
} | ||
|
||
public static function fromString(string $id): self | ||
{ | ||
return new self($id); | ||
} | ||
} | ||
``` | ||
|
||
So you can use it like this: | ||
|
||
```php | ||
use Patchlevel\EventSourcing\Aggregate\BasicAggregateRoot; | ||
use Patchlevel\EventSourcing\Attribute\Aggregate; | ||
use Patchlevel\EventSourcing\Attribute\Apply; | ||
|
||
use Ramsey\Uuid\UuidInterface; | ||
use Patchlevel\EventSourcing\Attribute\Id; | ||
use Patchlevel\EventSourcing\Serializer\Normalizer\IdNormalizer; | ||
|
||
#[Aggregate('profile')] | ||
final class Profile extends BasicAggregateRoot | ||
{ | ||
#[Id] | ||
#[IdNormalizer(ProfileId::class)] | ||
private ProfileId $id; | ||
private string $name; | ||
} | ||
``` | ||
|
||
public function aggregateRootId(): string | ||
{ | ||
return $this->id->toString(); | ||
} | ||
|
||
public function id(): ProfileId | ||
{ | ||
return $this->id; | ||
} | ||
|
||
public function name(): string | ||
{ | ||
return $this->name; | ||
} | ||
!!! note | ||
|
||
public static function create(string $name): self | ||
{ | ||
$id = ProfileId::generate(); | ||
|
||
$self = new self(); | ||
$self->recordThat(new ProfileCreated($id, $name)); | ||
If you want to use snapshots, then you have to make sure that the aggregate id are normalized. | ||
You can find how to do this [here](normalizer.md). | ||
|
||
return $self; | ||
} | ||
|
||
#[Apply] | ||
protected function applyProfileCreated(ProfileCreated $event): void | ||
{ | ||
$this->id = $event->profileId(); | ||
$this->name = $event->name(); | ||
} | ||
We also offer you some traits, so that you don't have to implement the `AggregateRootId` interface yourself. | ||
Here for the uuid: | ||
|
||
```php | ||
use Patchlevel\EventSourcing\Aggregate\AggregateRootId; | ||
use Patchlevel\EventSourcing\Aggregate\RamseyUuidBehaviour; | ||
use Patchlevel\EventSourcing\Aggregate\Uuid; | ||
|
||
class ProfileId implements AggregateRootId | ||
{ | ||
use RamseyUuidBehaviour; | ||
} | ||
``` | ||
|
||
!!! note | ||
Or for the custom id: | ||
|
||
If you want to use snapshots, then you have to make sure that the value objects are normalized. | ||
You can find how to do this [here](normalizer.md). | ||
```php | ||
use Patchlevel\EventSourcing\Aggregate\AggregateRootId; | ||
use Patchlevel\EventSourcing\Aggregate\CustomIdBehaviour; | ||
|
||
class ProfileId implements AggregateRootId | ||
{ | ||
use CustomIdBehaviour; | ||
} | ||
``` | ||
|
||
### Learn more | ||
|
||
* [How to create an aggregate](aggregate.md) | ||
* [How to create an event](events.md) | ||
* [How to test an aggregate](testing.md) | ||
* [How to normalize value objects](normalizer.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.