Skip to content

Commit

Permalink
clean-up aggregate id implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidBadura committed Jan 2, 2024
1 parent 59b7587 commit f8941c4
Show file tree
Hide file tree
Showing 40 changed files with 130 additions and 204 deletions.
48 changes: 24 additions & 24 deletions docs/pages/aggregate.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,22 @@ An aggregate must fulfill a few points so that we can use it in event-sourcing:

We can implement this ourselves, or use the `BasicAggregateRoot` implementation that already brings everything with it.
This basic implementation uses attributes to configure the aggregate and to specify how it should handle events.
We are building a minimal aggregate class here which only has an ID and mark this with the `AggregateId` attribute.
We are building a minimal aggregate class here which only has an ID and mark this with the `Id` attribute.
To make it easy to register with a name, we also add the `Aggregate` attribute. This is what it looks like:

```php
use Patchlevel\EventSourcing\Aggregate\BasicAggregateRoot;
use Patchlevel\EventSourcing\Aggregate\UuidAggregateRootId;
use Patchlevel\EventSourcing\Aggregate\Uuid;
use Patchlevel\EventSourcing\Attribute\Aggregate;
use Patchlevel\EventSourcing\Attribute\Id;

#[Aggregate('profile')]
final class Profile extends BasicAggregateRoot
{
#[Id]
private UuidAggregateRootId $id;
private Uuid $id;

public static function register(UuidAggregateRootId $id): self
public static function register(Uuid $id): self
{
$self = new self();

Expand Down Expand Up @@ -93,20 +93,20 @@ final class CreateProfileHandler
In order that an aggregate is actually saved, at least one event must exist in the DB.
For our aggregate we create the Event `ProfileRegistered` with an ID and a name.
Since the ID is a complex data type and cannot be easily serialized, we need to define a normalizer for the ID.
We do this with the `UuidAggregateIdNormalizer` attribute.
We do this with the `IdNormalizer` attribute.
We also give the event a unique name using the `Event` attribute.

```php
use Patchlevel\EventSourcing\Aggregate\UuidAggregateRootId;
use Patchlevel\EventSourcing\Aggregate\Uuid;
use Patchlevel\EventSourcing\Attribute\Event;
use Patchlevel\EventSourcing\Serializer\Normalizer\UuidAggregateIdNormalizer;
use Patchlevel\EventSourcing\Serializer\Normalizer\IdNormalizer;

#[Event('profile.registered')]
final class ProfileRegistered
{
public function __construct(
#[UuidAggregateIdNormalizer]
public readonly UuidAggregateRootId $profileId,
#[IdNormalizer(Uuid::class)]
public readonly Uuid $profileId,
public readonly string $name
) {}
}
Expand All @@ -120,7 +120,7 @@ After we have defined the event, we have to adapt the profile aggregate:

```php
use Patchlevel\EventSourcing\Aggregate\BasicAggregateRoot;
use Patchlevel\EventSourcing\Aggregate\UuidAggregateRootId;
use Patchlevel\EventSourcing\Aggregate\Uuid;
use Patchlevel\EventSourcing\Attribute\Aggregate;
use Patchlevel\EventSourcing\Attribute\Id;
use Patchlevel\EventSourcing\Attribute\Apply;
Expand All @@ -129,15 +129,15 @@ use Patchlevel\EventSourcing\Attribute\Apply;
final class Profile extends BasicAggregateRoot
{
#[Id]
private UuidAggregateRootId $id;
private Uuid $id;
private string $name;

public function name(): string
{
return $this->name;
}

public static function register(UuidAggregateRootId $id, string $name): self
public static function register(Uuid $id, string $name): self
{
$self = new self();
$self->recordThat(new ProfileRegistered($id, $name));
Expand Down Expand Up @@ -197,7 +197,7 @@ This method then creates the event `NameChanged` and records it:

```php
use Patchlevel\EventSourcing\Aggregate\BasicAggregateRoot;
use Patchlevel\EventSourcing\Aggregate\UuidAggregateRootId;
use Patchlevel\EventSourcing\Aggregate\Uuid;
use Patchlevel\EventSourcing\Attribute\Aggregate;
use Patchlevel\EventSourcing\Attribute\Id;
use Patchlevel\EventSourcing\Attribute\Apply;
Expand All @@ -206,15 +206,15 @@ use Patchlevel\EventSourcing\Attribute\Apply;
final class Profile extends BasicAggregateRoot
{
#[Id]
private UuidAggregateRootId $id;
private Uuid $id;
private string $name;

public function name(): string
{
return $this->name;
}

public static function register(UuidAggregateRootId $id, string $name): static
public static function register(Uuid $id, string $name): static
{
$self = new static();
$self->recordThat(new ProfileRegistered($id, $name));
Expand Down Expand Up @@ -444,7 +444,7 @@ We can now use the value object `Name` in our aggregate:

```php
use Patchlevel\EventSourcing\Aggregate\BasicAggregateRoot;
use Patchlevel\EventSourcing\Aggregate\UuidAggregateRootId;
use Patchlevel\EventSourcing\Aggregate\Uuid;
use Patchlevel\EventSourcing\Attribute\Aggregate;
use Patchlevel\EventSourcing\Attribute\Id;
use Patchlevel\EventSourcing\Attribute\Apply;
Expand All @@ -453,10 +453,10 @@ use Patchlevel\EventSourcing\Attribute\Apply;
final class Profile extends BasicAggregateRoot
{
#[Id]
private UuidAggregateRootId $id;
private Uuid $id;
private Name $name;

public static function register(UuidAggregateRootId $id, Name $name): static
public static function register(Uuid $id, Name $name): static
{
$self = new static();
$self->recordThat(new ProfileRegistered($id, $name));
Expand Down Expand Up @@ -563,7 +563,7 @@ But you can pass this information by yourself.

```php
use Patchlevel\EventSourcing\Aggregate\BasicAggregateRoot;
use Patchlevel\EventSourcing\Aggregate\UuidAggregateRootId;
use Patchlevel\EventSourcing\Aggregate\Uuid;
use Patchlevel\EventSourcing\Attribute\Aggregate;
use Patchlevel\EventSourcing\Attribute\Id;
use Patchlevel\EventSourcing\Attribute\Apply;
Expand All @@ -572,11 +572,11 @@ use Patchlevel\EventSourcing\Attribute\Apply;
final class Profile extends BasicAggregateRoot
{
#[Id]
private UuidAggregateRootId $id;
private Uuid $id;
private Name $name;
private DateTimeImmutable $registeredAt;

public static function register(UuidAggregateRootId $id, string $name, DateTimeImmutable $registeredAt): static
public static function register(Uuid $id, string $name, DateTimeImmutable $registeredAt): static
{
$self = new static();
$self->recordThat(new ProfileRegistered($id, $name, $registeredAt));
Expand All @@ -592,7 +592,7 @@ But if you still want to make sure that the time is "now" and not in the past or

```php
use Patchlevel\EventSourcing\Aggregate\BasicAggregateRoot;
use Patchlevel\EventSourcing\Aggregate\UuidAggregateRootId;
use Patchlevel\EventSourcing\Aggregate\Uuid;
use Patchlevel\EventSourcing\Attribute\Aggregate;
use Patchlevel\EventSourcing\Attribute\Id;
use Patchlevel\EventSourcing\Attribute\Apply;
Expand All @@ -602,11 +602,11 @@ use Patchlevel\EventSourcing\Clock\Clock;
final class Profile extends BasicAggregateRoot
{
#[Id]
private UuidAggregateRootId $id;
private Uuid $id;
private Name $name;
private DateTimeImmutable $registeredAt;

public static function register(UuidAggregateRootId $id, string $name, Clock $clock): static
public static function register(Uuid $id, string $name, Clock $clock): static
{
$self = new static();
$self->recordThat(new ProfileRegistered($id, $name, $clock->now()));
Expand Down
23 changes: 12 additions & 11 deletions docs/pages/getting_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ First we define the events that happen in our system.
A hotel can be created with a `name` and a `id`:

```php
use Patchlevel\EventSourcing\Aggregate\UuidAggregateRootId;
use Patchlevel\EventSourcing\Serializer\Normalizer\UuidAggregateIdNormalizer;
use Patchlevel\EventSourcing\Aggregate\Uuid;
use Patchlevel\EventSourcing\Serializer\Normalizer\IdNormalizer;

#[Event('hotel.created')]
final class HotelCreated
{
public function __construct(
#[UuidAggregateIdNormalizer]
public readonly UuidAggregateRootId $hotelId,
#[IdNormalizer(Uuid::class)]
public readonly Uuid $hotelId,
public readonly string $hotelName
) {
}
Expand Down Expand Up @@ -64,7 +64,7 @@ These events are thrown here and the state of the hotel is also changed.
```php
use Patchlevel\EventSourcing\Aggregate\AggregateChanged;
use Patchlevel\EventSourcing\Aggregate\BasicAggregateRoot;
use Patchlevel\EventSourcing\Aggregate\UuidAggregateRootId;
use Patchlevel\EventSourcing\Aggregate\Uuid;
use Patchlevel\EventSourcing\Attribute\Aggregate;
use Patchlevel\EventSourcing\Attribute\Id;
use Patchlevel\EventSourcing\Attribute\Apply;
Expand All @@ -73,7 +73,7 @@ use Patchlevel\EventSourcing\Attribute\Apply;
final class Hotel extends BasicAggregateRoot
{
#[Id]
private UuidAggregateRootId $id;
private Uuid $id;
private string $name;

/**
Expand All @@ -91,7 +91,7 @@ final class Hotel extends BasicAggregateRoot
return $this->guests;
}

public static function create(UuidAggregateRootId $id, string $hotelName): static
public static function create(Uuid $id, string $hotelName): static
{
$self = new static();
$self->recordThat(new HotelCreated($id, $hotelName));
Expand Down Expand Up @@ -366,16 +366,16 @@ $projectionist->boot();
We are now ready to use the Event Sourcing System. We can load, change and save aggregates.

```php
use Patchlevel\EventSourcing\Aggregate\UuidAggregateRootId;
use Patchlevel\EventSourcing\Aggregate\Uuid;

$hotel1 = Hotel::create(UuidAggregateRootId::generate(), 'HOTEL');
$hotel1 = Hotel::create(Uuid::v7(), 'HOTEL');
$hotel1->checkIn('David');
$hotel1->checkIn('Daniel');
$hotel1->checkOut('David');

$hotelRepository->save($hotel1);

$hotel2 = $hotelRepository->load(UuidAggregateRootId::fromString('d0d0d0d0-d0d0-d0d0-d0d0-d0d0d0d0d0d0'));
$hotel2 = $hotelRepository->load(Uuid::fromString('d0d0d0d0-d0d0-d0d0-d0d0-d0d0d0d0d0d0'));
$hotel2->checkIn('David');
$hotelRepository->save($hotel2);

Expand All @@ -384,7 +384,8 @@ $hotels = $hotelProjection->getHotels();

!!! note

An aggregateId can be an **uuid**, you can find more about this [here](uuid.md).
You can also use other forms of IDs such as uuid version 6 or a custom format.
You can find more about this [here](aggregate_id.md).

## Result

Expand Down
41 changes: 7 additions & 34 deletions docs/pages/normalizer.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,45 +200,18 @@ final class DTO {
}
```

### UuidAggregateId
### Id

To normalize a `UuidAggregateRootId` one can use the `UuidAggregateIdNormalizer`.
If you have your own AggregateRootId, you can use the `IdNormalizer`.
the `IdNormalizer` needs the FQCN of the AggregateRootId as a parameter.

```php
use Patchlevel\EventSourcing\Aggregate\UuidAggregateRootId;
use Patchlevel\Hydrator\Normalizer\UuidAggregateIdNormalizer;
use Patchlevel\EventSourcing\Aggregate\Uuid;
use Patchlevel\Hydrator\Normalizer\IdNormalizer;

final class DTO {
#[UuidAggregateIdNormalizer]
public UuidAggregateRootId $id;
}
```

### BasicAggregateIdNormalizer

To normalize a `ValueAggregateRootId` one can use the `BasicAggregateIdNormalizer`.

```php
use Patchlevel\EventSourcing\Aggregate\ValueAggregateRootId;
use Patchlevel\Hydrator\Normalizer\BasicAggregateIdNormalizer;

final class DTO {
#[BasicAggregateIdNormalizer]
public ValueAggregateRootId $id;
}
```

### Own AggregateId

If you have your own AggregateId, you can use the `AggregateIdNormalizer` base normalizer.
the `AggregateIdNormalizer` needs the FQCN of the AggregateId as a parameter.

```php
use Patchlevel\Hydrator\Normalizer\AggregateIdNormalizer;

final class DTO {
#[AggregateIdNormalizer(Id::class)]
public Id $id;
#[IdNormalizer(Uuid::class)]
public Uuid $id;
}
```

Expand Down
10 changes: 5 additions & 5 deletions docs/pages/repository.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,9 @@ After the events have been written,
the new events are dispatched on the [event bus](./event_bus.md).

```php
use Patchlevel\EventSourcing\Aggregate\UuidAggregateRootId;
use Patchlevel\EventSourcing\Aggregate\Uuid;

$id = UuidAggregateRootId::generate();
$id = Uuid::v7();
$profile = Profile::create($id, '[email protected]');

$repository->save($profile);
Expand All @@ -126,9 +126,9 @@ An `aggregate` can be loaded using the `load` method.
All events for the aggregate are loaded from the database and the current state is rebuilt.

```php
use Patchlevel\EventSourcing\Aggregate\UuidAggregateRootId;
use Patchlevel\EventSourcing\Aggregate\Uuid;

$id = UuidAggregateRootId::fromString('229286ff-6f95-4df6-bc72-0a239fe7b284');
$id = Uuid::fromString('229286ff-6f95-4df6-bc72-0a239fe7b284');
$profile = $repository->load($id);
```

Expand All @@ -147,7 +147,7 @@ You can also check whether an `aggregate` with a certain id exists.
It is checked whether any event with this id exists in the database.

```php
$id = UuidAggregateRootId::fromString('229286ff-6f95-4df6-bc72-0a239fe7b284');
$id = Uuid::fromString('229286ff-6f95-4df6-bc72-0a239fe7b284');

if($repository->has($id)) {
// ...
Expand Down
11 changes: 6 additions & 5 deletions docs/pages/snapshots.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,18 +72,19 @@ You can define normalizers to bring the properties into the correct format.

```php
use Patchlevel\EventSourcing\Aggregate\BasicAggregateRoot;
use Patchlevel\EventSourcing\Aggregate\UuidAggregateRootId;
use Patchlevel\EventSourcing\Aggregate\Uuid;
use Patchlevel\EventSourcing\Attribute\Aggregate;
use Patchlevel\EventSourcing\Attribute\Id;
use Patchlevel\EventSourcing\Attribute\Snapshot;
use Patchlevel\EventSourcing\Serializer\Normalizer\IdNormalizer;

#[Aggregate('profile')]
#[Snapshot('default')]
final class Profile extends BasicAggregateRoot
{
#[Id]
#[UuidAggregateRootIdNormalizer]
public UuidAggregateRootId $id;
#[IdNormalizer]
public Uuid $id;
public string $name,
#[Normalize(new DateTimeImmutableNormalizer())]
public DateTimeImmutable $createdAt;
Expand Down Expand Up @@ -221,9 +222,9 @@ $snapshotStore->save($aggregate);
You can also load an aggregate from the snapshot store:

```php
use Patchlevel\EventSourcing\Aggregate\UuidAggregateRootId;
use Patchlevel\EventSourcing\Aggregate\Uuid;

$id = UuidAggregateRootId::fromString('229286ff-6f95-4df6-bc72-0a239fe7b284');
$id = Uuid::fromString('229286ff-6f95-4df6-bc72-0a239fe7b284');
$aggregate = $snapshotStore->load(Profile::class, $id);
```

Expand Down
10 changes: 0 additions & 10 deletions src/Aggregate/BasicAggregateRootId.php

This file was deleted.

10 changes: 10 additions & 0 deletions src/Aggregate/CustomId.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

namespace Patchlevel\EventSourcing\Aggregate;

final class CustomId implements AggregateRootId
{
use CustomIdBehaviour;
}
Loading

0 comments on commit f8941c4

Please sign in to comment.