Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[EventSourcing] Experimenting with new way to complete things to make it a little easier #111

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,4 @@
/src/SonsOfPHP/Component/Queue @JoshuaEstes
/src/SonsOfPHP/Component/Version @JoshuaEstes
/src/SonsOfPHP/Contract/Core @JoshuaEstes
/src/SonsOfPHP/Contract/EventSourcing @JoshuaEstes
1 change: 1 addition & 0 deletions .github/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,4 @@ Contracts:

documentation:
- docs/**
- mkdocs.yml
65 changes: 65 additions & 0 deletions docs/components/event-sourcing/aggregates/aggregate-id.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
---
title: Aggregate IDs
---

# Aggregate IDs

Each Aggregate will need to have it's own unique ID. You can use the same
AggregateId class for all your aggregates or you can make you own for each one
to ensure data consistency.

### Working with an Aggregate ID

```php
<?php

use SonsOfPHP\Component\EventSourcing\Aggregate\AggregateId;

// Create a new Aggregate ID
$aggregateId = new AggregateId('my-unique-id');

// You can get the value of the ID
$id = $aggregateId->toString();
$id = (string) $aggregateId;

// To compare two Aggregate IDs
if ($aggregateId->equals($anotherAggregateId)) {
// they are the same
}
```

If you need to create an Aggregate ID Class in order to use type-hinting, just
extend the `AbstractAggregateId` class.

```php
<?php

use SonsOfPHP\Component\EventSourcing\Aggregate\AbstractAggregateId;

final class UserId extends AbstractAggregateId
{
}
```

#### Auto Generate Aggregate IDs

!!! attention
This requires the installation of the `sonsofphp/event-sourcing-symfony` package.

Creating your own implementation to generate UUIDs or other type of IDs can be a
pain in the ass. Once the `sonsofphp/event-sourcing-symfony` package is
installed, you can easily use Symfony's Uid Component to generate UUIDs for you.

```php
<?php
use SonsOfPHP\Bridge\Symfony\EventSourcing\AggregateId;
use Symfony\Component\Uid\Uuid;
use Symfony\Component\Uid\Ulid;

$id = new AggregateId();

Uuid::isValid($id->toString()); // true

// It also still supports setting the ID via the constructor
$ulid = new AggregateId((string) new Ulid());
```
26 changes: 26 additions & 0 deletions docs/components/event-sourcing/aggregates/aggregate-version.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
title: Aggregate Versions
---

# Aggregate Version

An Aggregate also has a version. Each event that is raised will increase the
version. You will generally not have to work much with versions as they are
mostly handled internally.

### Working with an Aggregate Version

```php
<?php
use SonsOfPHP\Component\EventSourcing\Aggregate\AggregateVersion;

$aggregateVersion = new AggregateVersion();

// Get the version
$version = $aggregateVersion->toInt();

// Comparing Versions
if ($aggregateVersion->equals($anotherAggregateVersion)) {
// they are the same
}
```
84 changes: 0 additions & 84 deletions docs/components/event-sourcing/aggregates/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,90 +6,6 @@ title: Aggregates

Aggregates are the primary objects that you will be working with.

## Aggregate ID

Each Aggregate will need to have it's own unique ID. You can use the same
AggregateId class for all your aggregates or you can make you own for each one
to ensure data consistency.

### Working with an Aggregate ID

```php
<?php
use SonsOfPHP\Component\EventSourcing\Aggregate\AggregateId;

// Create a new Aggregate ID
$aggregateId = new AggregateId('my-unique-id');

// You can get the value of the ID
$id = $aggregateId->toString();
$id = (string) $aggregateId;

// To compare two Aggregate IDs
if ($aggregateId->equals($anotherAggregateId)) {
// they are the same
}
```

If you need to create an Aggregate ID Class in order to use type-hinting, just
extend the `AbstractAggregateId` class.

```php
<?php
use SonsOfPHP\Component\EventSourcing\Aggregate\AbstractAggregateId;

final class UserId extends AbstractAggregateId
{
}
```

#### Auto Generate Aggregate IDs

!!! attention
This requires the installation of the `sonsofphp/event-sourcing-symfony` package.

Creating your own implementation to generate UUIDs or other type of IDs can be a
pain in the ass. Once the `sonsofphp/event-sourcing-symfony` package is
installed, you can easily use Symfony's Uid Component to generate UUIDs for you.

```php
<?php
use SonsOfPHP\Bridge\Symfony\EventSourcing\AggregateId;
use Symfony\Component\Uid\Uuid;
use Symfony\Component\Uid\Ulid;

$id = new AggregateId();

Uuid::isValid($id->toString()); // true

// It also still supports setting the ID via the constructor
$ulid = new AggregateId((string) new Ulid());
```


## Aggregate Version

An Aggregate also has a version. Each event that is raised will increase the
version. You will generally not have to work much with versions as they are
mostly handled internally.

### Working with an Aggregate Version

```php
<?php
use SonsOfPHP\Component\EventSourcing\Aggregate\AggregateVersion;

$aggregateVersion = new AggregateVersion();

// Get the version
$version = $aggregateVersion->toInt();

// Comparing Versions
if ($aggregateVersion->equals($anotherAggregateVersion)) {
// they are the same
}
```

## Creating an Aggregate

Pretty simple to create an aggregate.
Expand Down
2 changes: 1 addition & 1 deletion docs/contracts/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Contracts are interfaces that can be reusable across multiple different
libraries and projects. The actual implementation of the interfaces is left up
to you.

The interfaces also enhance existing PSRs.
The interfaces may also enhance existing PSRs.

Whenever possible, the components and projects created by Sons of PHP will
implement these interfaces.
Expand Down
2 changes: 2 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ nav:
- components/event-sourcing/index.md
- Aggregates:
- components/event-sourcing/aggregates/index.md
- Aggregate ID: components/event-sourcing/aggregates/aggregate-id.md
- Aggregate Version: components/event-sourcing/aggregates/aggregate-version.md
- Storage:
- components/event-sourcing/aggregates/storage/index.md
- Event Messages:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,16 @@ final public function __construct(AggregateIdInterface|string $id)
}

/**
* @param AggregateIdInterface|string $id
*
* @return static
* {@inheritdoc}
*/
final public static function new($id)
{
@trigger_error(sprintf('"%s::new()" is deprecated, use "new %s()" instead.', static::class, static::class), \E_USER_DEPRECATED);
$static = new static($id);

return $static;
}

final public function getAggregateId(): AggregateIdInterface
{
return $this->id;
}

/**
* {@inheritdoc}
*/
final public function getAggregateVersion(): AggregateVersionInterface
{
return $this->version;
Expand All @@ -59,6 +52,9 @@ final public function hasPendingEvents(): bool
return \count($this->pendingEvents) > 0;
}

/**
* {@inheritdoc}
*/
final public function getPendingEvents(): iterable
{
$events = $this->pendingEvents;
Expand All @@ -67,12 +63,18 @@ final public function getPendingEvents(): iterable
return $events;
}

/**
* {@inheritdoc}
*/
final public function peekPendingEvents(): iterable
{
return $this->pendingEvents;
}

final public static function buildFromEvents(AggregateIdInterface $id, \Generator $events): AggregateInterface
/**
* {@inheritdoc}
*/
final public static function buildFromEvents(AggregateIdInterface $id, iterable $events): AggregateInterface
{
$aggregate = new static($id);
foreach ($events as $event) {
Expand Down Expand Up @@ -124,7 +126,7 @@ final protected function applyEvent(MessageInterface $event): void
$method = 'apply' . end($parts);

if (method_exists($this, $method)) {
$this->{$method}($event); // @phpstan-ignore-line
$this->{$method}($event);
}

$this->version = $this->version->next();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,30 @@ public function __construct(
}
}

/**
* {@inheritdoc}
*/
final public function __toString(): string
{
return $this->toString();
}

final public function toString(): string
final public static function fromString(string $id): AggregateIdInterface
{
return $this->id;
return new static($id);
}

final public static function fromString(string $id): AggregateIdInterface
/**
* {@inheritdoc}
*/
final public function toString(): string
{
return new static($id);
return $this->id;
}

/**
* {@inheritdoc}
*/
final public function equals(AggregateIdInterface $that): bool
{
return $this->toString() === $that->toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,11 @@ public function __toString(): string;
*/
public function toString(): string;

/**
* Creates an instance of AggregateIdInterface with the passed in
* value.
*
* Example:
* $id = AggregateId::fromString('unique-uuid');
*
* @throws EventSourcingException
*/
public static function fromString(string $id): self;

/**
* Compares two Aggregate ID objects and returns true if they are
* equal.
*
* @throws EventSourcingException
*/
public function equals(self $that): bool;
public function equals(AggregateIdInterface $that): bool;
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ public function peekPendingEvents(): iterable;
/**
* Build Aggregate from a collection of Domain Events.
*
* @param \Generator $events yields MessageInterface objects
* @param iterable $events yields MessageInterface objects
*
* @throws EventSourcingException
*/
public static function buildFromEvents(AggregateIdInterface $id, \Generator $events): self;
public static function buildFromEvents(AggregateIdInterface $id, iterable $events): self;
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,15 @@
*/
interface SnapshotableAggregateInterface extends AggregateInterface
{
/**
*/
public function createSnapshot(): SnapshotInterface;

/**
*/
public static function buildFromSnapshot(SnapshotInterface $snapshot): self;

public static function buildFromSnapshotAndEvents(SnapshotInterface $snapshot, \Generator $events): self;
/**
*/
public static function buildFromSnapshotAndEvents(SnapshotInterface $snapshot, iterable $events): self;
}
Loading
Loading