diff --git a/src/Aggregate/AggregateIdNotFound.php b/src/Aggregate/AggregateIdNotFound.php new file mode 100644 index 000000000..669ba1f99 --- /dev/null +++ b/src/Aggregate/AggregateIdNotFound.php @@ -0,0 +1,18 @@ + $events */ public function catchUp(iterable $events): void; diff --git a/src/Aggregate/AggregateRootAttributeBehaviour.php b/src/Aggregate/AggregateRootAttributeBehaviour.php index e8756081f..29efa384d 100644 --- a/src/Aggregate/AggregateRootAttributeBehaviour.php +++ b/src/Aggregate/AggregateRootAttributeBehaviour.php @@ -4,6 +4,8 @@ namespace Patchlevel\EventSourcing\Aggregate; +use ReflectionProperty; + use function array_key_exists; trait AggregateRootAttributeBehaviour @@ -11,6 +13,8 @@ trait AggregateRootAttributeBehaviour use AggregateRootBehaviour; use AggregateRootMetadataAwareBehaviour; + private AggregateRootId|null $_aggregateRootId = null; + protected function apply(object $event): void { $metadata = static::metadata(); @@ -26,4 +30,24 @@ protected function apply(object $event): void $method = $metadata->applyMethods[$event::class]; $this->$method($event); } + + public function aggregateRootId(): AggregateRootId + { + if ($this->_aggregateRootId instanceof AggregateRootId) { + return $this->_aggregateRootId; + } + + $metadata = static::metadata(); + + $reflection = new ReflectionProperty($this, $metadata->idProperty); + + /** @var mixed $aggregateId */ + $aggregateId = $reflection->getValue($this); + + if (!$aggregateId instanceof AggregateRootId) { + throw new AggregateIdNotFound($this::class); + } + + return $this->_aggregateRootId = $aggregateId; + } } diff --git a/src/Aggregate/AggregateRootId.php b/src/Aggregate/AggregateRootId.php new file mode 100644 index 000000000..3ce2a1cda --- /dev/null +++ b/src/Aggregate/AggregateRootId.php @@ -0,0 +1,10 @@ +id; + } +} diff --git a/src/Attribute/AggregateId.php b/src/Attribute/AggregateId.php new file mode 100644 index 000000000..bd345d4b7 --- /dev/null +++ b/src/Attribute/AggregateId.php @@ -0,0 +1,12 @@ + */ public readonly string $className, public readonly string $name, + public readonly string $idProperty, /** @var array */ public readonly array $applyMethods, /** @var array */ diff --git a/src/Metadata/AggregateRoot/AttributeAggregateRootMetadataFactory.php b/src/Metadata/AggregateRoot/AttributeAggregateRootMetadataFactory.php index 74b8cd39b..e6f2482db 100644 --- a/src/Metadata/AggregateRoot/AttributeAggregateRootMetadataFactory.php +++ b/src/Metadata/AggregateRoot/AttributeAggregateRootMetadataFactory.php @@ -6,6 +6,7 @@ use Patchlevel\EventSourcing\Aggregate\AggregateRoot; use Patchlevel\EventSourcing\Attribute\Aggregate; +use Patchlevel\EventSourcing\Attribute\AggregateId; use Patchlevel\EventSourcing\Attribute\Apply; use Patchlevel\EventSourcing\Attribute\Snapshot as AttributeSnapshot; use Patchlevel\EventSourcing\Attribute\SuppressMissingApply; @@ -41,6 +42,7 @@ public function metadata(string $aggregate): AggregateRootMetadata $reflector = new ReflectionClass($aggregate); $aggregateName = $this->findAggregateName($reflector); + $idProperty = $this->findIdProperty($reflector); [$suppressEvents, $suppressAll] = $this->findSuppressMissingApply($reflector); $applyMethods = $this->findApplyMethods($reflector, $aggregate); $snapshot = $this->findSnapshot($reflector); @@ -48,6 +50,7 @@ public function metadata(string $aggregate): AggregateRootMetadata $metadata = new AggregateRootMetadata( $aggregate, $aggregateName, + $idProperty, $applyMethods, $suppressEvents, $suppressAll, @@ -97,6 +100,23 @@ private function findAggregateName(ReflectionClass $reflector): string return $aggregateAttribute->name(); } + private function findIdProperty(ReflectionClass $reflector): string + { + $properties = $reflector->getProperties(); + + foreach ($properties as $property) { + $attributes = $property->getAttributes(AggregateId::class); + + if ($attributes === []) { + continue; + } + + return $property->getName(); + } + + throw new AggregateIdNotFound($reflector->getName()); + } + private function findSnapshot(ReflectionClass $reflector): Snapshot|null { $attributeReflectionList = $reflector->getAttributes(AttributeSnapshot::class); diff --git a/src/Repository/AggregateDetached.php b/src/Repository/AggregateDetached.php index f213838fb..faa7b0f8e 100644 --- a/src/Repository/AggregateDetached.php +++ b/src/Repository/AggregateDetached.php @@ -5,19 +5,20 @@ namespace Patchlevel\EventSourcing\Repository; use Patchlevel\EventSourcing\Aggregate\AggregateRoot; +use Patchlevel\EventSourcing\Aggregate\AggregateRootId; use function sprintf; final class AggregateDetached extends RepositoryException { /** @param class-string $aggregateClass */ - public function __construct(string $aggregateClass, string $aggregateId) + public function __construct(string $aggregateClass, AggregateRootId $aggregateId) { parent::__construct( sprintf( 'An error occurred while saving the aggregate "%s" with the ID "%s", causing the uncommitted events to be lost. Please reload the aggregate.', $aggregateClass, - $aggregateId, + $aggregateId->toString(), ), ); } diff --git a/src/Repository/AggregateNotFound.php b/src/Repository/AggregateNotFound.php index 07d40b75b..7b46eaf4e 100644 --- a/src/Repository/AggregateNotFound.php +++ b/src/Repository/AggregateNotFound.php @@ -4,12 +4,14 @@ namespace Patchlevel\EventSourcing\Repository; +use Patchlevel\EventSourcing\Aggregate\AggregateRootId; + use function sprintf; final class AggregateNotFound extends RepositoryException { - public function __construct(string $aggregateClass, string $id) + public function __construct(string $aggregateClass, AggregateRootId $id) { - parent::__construct(sprintf('aggregate "%s::%s" not found', $aggregateClass, $id)); + parent::__construct(sprintf('aggregate "%s::%s" not found', $aggregateClass, $id->toString())); } } diff --git a/src/Repository/AggregateUnknown.php b/src/Repository/AggregateUnknown.php index d7889811c..8a7277ef3 100644 --- a/src/Repository/AggregateUnknown.php +++ b/src/Repository/AggregateUnknown.php @@ -5,19 +5,20 @@ namespace Patchlevel\EventSourcing\Repository; use Patchlevel\EventSourcing\Aggregate\AggregateRoot; +use Patchlevel\EventSourcing\Aggregate\AggregateRootId; use function sprintf; final class AggregateUnknown extends RepositoryException { /** @param class-string $aggregateClass */ - public function __construct(string $aggregateClass, string $aggregateId) + public function __construct(string $aggregateClass, AggregateRootId $aggregateId) { parent::__construct( sprintf( 'The aggregate %s with the ID "%s" was not loaded from this repository. Please reload the aggregate.', $aggregateClass, - $aggregateId, + $aggregateId->toString(), ), ); } diff --git a/src/Repository/DefaultRepository.php b/src/Repository/DefaultRepository.php index c313a71e8..c6eb7fe28 100644 --- a/src/Repository/DefaultRepository.php +++ b/src/Repository/DefaultRepository.php @@ -5,6 +5,7 @@ namespace Patchlevel\EventSourcing\Repository; use Patchlevel\EventSourcing\Aggregate\AggregateRoot; +use Patchlevel\EventSourcing\Aggregate\AggregateRootId; use Patchlevel\EventSourcing\Clock\SystemClock; use Patchlevel\EventSourcing\EventBus\Decorator\MessageDecorator; use Patchlevel\EventSourcing\EventBus\EventBus; @@ -57,7 +58,7 @@ public function __construct( } /** @return T */ - public function load(string $id): AggregateRoot + public function load(AggregateRootId $id): AggregateRoot { if ($this->snapshotStore && $this->metadata->snapshot) { try { @@ -69,7 +70,7 @@ public function load(string $id): AggregateRoot sprintf( 'snapshot for aggregate "%s" with the id "%s" not found', $this->metadata->className, - $id, + $id->toString(), ), ); } catch (SnapshotVersionInvalid) { @@ -77,7 +78,7 @@ public function load(string $id): AggregateRoot sprintf( 'snapshot for aggregate "%s" with the id "%s" is invalid', $this->metadata->className, - $id, + $id->toString(), ), ); } @@ -85,7 +86,7 @@ public function load(string $id): AggregateRoot $criteria = (new CriteriaBuilder()) ->aggregateClass($this->metadata->className) - ->aggregateId($id) + ->aggregateId($id->toString()) ->archived(false) ->build(); @@ -117,11 +118,11 @@ public function load(string $id): AggregateRoot return $aggregate; } - public function has(string $id): bool + public function has(AggregateRootId $id): bool { $criteria = (new CriteriaBuilder()) ->aggregateClass($this->metadata->className) - ->aggregateId($id) + ->aggregateId($id->toString()) ->build(); return $this->store->count($criteria) > 0; @@ -162,7 +163,7 @@ public function save(AggregateRoot $aggregate): void static function (object $event) use ($aggregate, &$playhead, $messageDecorator, $clock) { $message = Message::create($event) ->withAggregateClass($aggregate::class) - ->withAggregateId($aggregate->aggregateRootId()) + ->withAggregateId($aggregate->aggregateRootId()->toString()) ->withPlayhead(++$playhead) ->withRecordedOn($clock->now()); @@ -194,7 +195,7 @@ static function (object $event) use ($aggregate, &$playhead, $messageDecorator, * * @return T */ - private function loadFromSnapshot(string $aggregateClass, string $id): AggregateRoot + private function loadFromSnapshot(string $aggregateClass, AggregateRootId $id): AggregateRoot { assert($this->snapshotStore instanceof SnapshotStore); @@ -202,7 +203,7 @@ private function loadFromSnapshot(string $aggregateClass, string $id): Aggregate $criteria = (new CriteriaBuilder()) ->aggregateClass($this->metadata->className) - ->aggregateId($id) + ->aggregateId($id->toString()) ->fromPlayhead($aggregate->playhead()) ->build(); diff --git a/src/Repository/PlayheadMismatch.php b/src/Repository/PlayheadMismatch.php index 54eaaecff..82175e097 100644 --- a/src/Repository/PlayheadMismatch.php +++ b/src/Repository/PlayheadMismatch.php @@ -4,18 +4,20 @@ namespace Patchlevel\EventSourcing\Repository; +use Patchlevel\EventSourcing\Aggregate\AggregateRootId; + use function sprintf; final class PlayheadMismatch extends RepositoryException { - public function __construct(string $aggregateClass, string $aggregateId, int $playhead, int $eventCount) + public function __construct(string $aggregateClass, AggregateRootId $aggregateId, int $playhead, int $eventCount) { parent::__construct(sprintf( 'There is a mismatch between the playhead [%s] and the event count [%s] for the aggregate [%s] with the id [%s]', $playhead, $eventCount, $aggregateClass, - $aggregateId, + $aggregateId->toString(), )); } } diff --git a/src/Repository/Repository.php b/src/Repository/Repository.php index 253732aa3..1ad8f36c4 100644 --- a/src/Repository/Repository.php +++ b/src/Repository/Repository.php @@ -5,14 +5,15 @@ namespace Patchlevel\EventSourcing\Repository; use Patchlevel\EventSourcing\Aggregate\AggregateRoot; +use Patchlevel\EventSourcing\Aggregate\AggregateRootId; /** @template T of AggregateRoot */ interface Repository { /** @return T */ - public function load(string $id): AggregateRoot; + public function load(AggregateRootId $id): AggregateRoot; - public function has(string $id): bool; + public function has(AggregateRootId $id): bool; /** @param T $aggregate */ public function save(AggregateRoot $aggregate): void; diff --git a/src/Repository/SnapshotRebuildFailed.php b/src/Repository/SnapshotRebuildFailed.php index 9c46ab2ac..29d7962d3 100644 --- a/src/Repository/SnapshotRebuildFailed.php +++ b/src/Repository/SnapshotRebuildFailed.php @@ -5,6 +5,7 @@ namespace Patchlevel\EventSourcing\Repository; use Patchlevel\EventSourcing\Aggregate\AggregateRoot; +use Patchlevel\EventSourcing\Aggregate\AggregateRootId; use Throwable; use function sprintf; @@ -14,14 +15,14 @@ final class SnapshotRebuildFailed extends RepositoryException /** @param class-string $aggregateClass */ public function __construct( private string $aggregateClass, - private string $aggregateId, + private AggregateRootId $aggregateId, Throwable $previous, ) { parent::__construct( sprintf( 'Rebuild from snapshot of aggregate "%s" with the id "%s" failed', $aggregateClass, - $aggregateId, + $aggregateId->toString(), ), 0, $previous, @@ -34,7 +35,7 @@ public function aggregateClass(): string return $this->aggregateClass; } - public function aggregateId(): string + public function aggregateId(): AggregateRootId { return $this->aggregateId; } diff --git a/src/Snapshot/DefaultSnapshotStore.php b/src/Snapshot/DefaultSnapshotStore.php index eddafee69..08ddbaaa6 100644 --- a/src/Snapshot/DefaultSnapshotStore.php +++ b/src/Snapshot/DefaultSnapshotStore.php @@ -5,6 +5,7 @@ namespace Patchlevel\EventSourcing\Snapshot; use Patchlevel\EventSourcing\Aggregate\AggregateRoot; +use Patchlevel\EventSourcing\Aggregate\AggregateRootId; use Patchlevel\EventSourcing\Metadata\AggregateRoot\AggregateRootMetadataAwareMetadataFactory; use Patchlevel\EventSourcing\Metadata\AggregateRoot\AggregateRootMetadataFactory; use Patchlevel\EventSourcing\Snapshot\Adapter\SnapshotAdapter; @@ -56,7 +57,7 @@ public function save(AggregateRoot $aggregateRoot): void * * @template T of AggregateRoot */ - public function load(string $aggregateClass, string $id): AggregateRoot + public function load(string $aggregateClass, AggregateRootId $id): AggregateRoot { $adapter = $this->adapter($aggregateClass); $key = $this->key($aggregateClass, $id); @@ -98,11 +99,11 @@ public function adapter(string $aggregateClass): SnapshotAdapter } /** @param class-string $aggregateClass */ - private function key(string $aggregateClass, string $aggregateId): string + private function key(string $aggregateClass, AggregateRootId $aggregateId): string { $aggregateName = $this->metadataFactory->metadata($aggregateClass)->name; - return sprintf('%s-%s', $aggregateName, $aggregateId); + return sprintf('%s-%s', $aggregateName, $aggregateId->toString()); } /** @param class-string $aggregateClass */ diff --git a/src/Snapshot/SnapshotNotFound.php b/src/Snapshot/SnapshotNotFound.php index 455de4924..d606d0ca4 100644 --- a/src/Snapshot/SnapshotNotFound.php +++ b/src/Snapshot/SnapshotNotFound.php @@ -5,6 +5,7 @@ namespace Patchlevel\EventSourcing\Snapshot; use Patchlevel\EventSourcing\Aggregate\AggregateRoot; +use Patchlevel\EventSourcing\Aggregate\AggregateRootId; use Throwable; use function sprintf; @@ -12,13 +13,13 @@ final class SnapshotNotFound extends SnapshotException { /** @param class-string $aggregate */ - public function __construct(string $aggregate, string $id, Throwable|null $previous = null) + public function __construct(string $aggregate, AggregateRootId $id, Throwable|null $previous = null) { parent::__construct( sprintf( 'snapshot for aggregate "%s" with the id "%s" not found', $aggregate, - $id, + $id->toString(), ), 0, $previous, diff --git a/src/Snapshot/SnapshotStore.php b/src/Snapshot/SnapshotStore.php index d0bc2ee74..d6d14d339 100644 --- a/src/Snapshot/SnapshotStore.php +++ b/src/Snapshot/SnapshotStore.php @@ -5,6 +5,7 @@ namespace Patchlevel\EventSourcing\Snapshot; use Patchlevel\EventSourcing\Aggregate\AggregateRoot; +use Patchlevel\EventSourcing\Aggregate\AggregateRootId; use Patchlevel\EventSourcing\Snapshot\Adapter\SnapshotNotFound; interface SnapshotStore @@ -20,5 +21,5 @@ public function save(AggregateRoot $aggregateRoot): void; * * @template T of AggregateRoot */ - public function load(string $aggregateClass, string $id): AggregateRoot; + public function load(string $aggregateClass, AggregateRootId $id): AggregateRoot; } diff --git a/tests/Integration/BankAccountSplitStream/Aggregate/BankAccount.php b/tests/Integration/BankAccountSplitStream/Aggregate/BankAccount.php index 609ddd0d3..00f5edc2c 100644 --- a/tests/Integration/BankAccountSplitStream/Aggregate/BankAccount.php +++ b/tests/Integration/BankAccountSplitStream/Aggregate/BankAccount.php @@ -6,28 +6,23 @@ use Patchlevel\EventSourcing\Aggregate\BasicAggregateRoot; use Patchlevel\EventSourcing\Attribute\Aggregate; +use Patchlevel\EventSourcing\Attribute\AggregateId; use Patchlevel\EventSourcing\Attribute\Apply; use Patchlevel\EventSourcing\Tests\Integration\BankAccountSplitStream\AccountId; use Patchlevel\EventSourcing\Tests\Integration\BankAccountSplitStream\Events\BalanceAdded; use Patchlevel\EventSourcing\Tests\Integration\BankAccountSplitStream\Events\BankAccountCreated; use Patchlevel\EventSourcing\Tests\Integration\BankAccountSplitStream\Events\MonthPassed; -use Patchlevel\EventSourcing\Tests\Integration\BankAccountSplitStream\Normalizer\AccountIdNormalizer; #[Aggregate('profile')] final class BankAccount extends BasicAggregateRoot { - #[AccountIdNormalizer] + #[AggregateId] private AccountId $id; private string $name; private int $balanceInCents; /** @var list */ public array $appliedEvents = []; - public function aggregateRootId(): string - { - return $this->id->toString(); - } - public static function create(AccountId $id, string $name): self { $self = new self(); diff --git a/tests/Integration/BasicImplementation/Aggregate/Profile.php b/tests/Integration/BasicImplementation/Aggregate/Profile.php index bd77fdc79..5c65679cc 100644 --- a/tests/Integration/BasicImplementation/Aggregate/Profile.php +++ b/tests/Integration/BasicImplementation/Aggregate/Profile.php @@ -6,6 +6,7 @@ use Patchlevel\EventSourcing\Aggregate\BasicAggregateRoot; use Patchlevel\EventSourcing\Attribute\Aggregate; +use Patchlevel\EventSourcing\Attribute\AggregateId; use Patchlevel\EventSourcing\Attribute\Apply; use Patchlevel\EventSourcing\Attribute\Snapshot; use Patchlevel\EventSourcing\Tests\Integration\BasicImplementation\Events\ProfileCreated; @@ -16,15 +17,11 @@ #[Snapshot('default', 100)] final class Profile extends BasicAggregateRoot { + #[AggregateId] #[ProfileIdNormalizer] private ProfileId $id; private string $name; - public function aggregateRootId(): string - { - return $this->id->toString(); - } - public static function create(ProfileId $id, string $name): self { $self = new self(); diff --git a/tests/Integration/Outbox/Aggregate/Profile.php b/tests/Integration/Outbox/Aggregate/Profile.php index b4ceda4fd..03731c1eb 100644 --- a/tests/Integration/Outbox/Aggregate/Profile.php +++ b/tests/Integration/Outbox/Aggregate/Profile.php @@ -16,15 +16,11 @@ #[Snapshot('default', 100)] final class Profile extends BasicAggregateRoot { + #[AggregateId] #[ProfileIdNormalizer] private ProfileId $id; private string $name; - public function aggregateRootId(): string - { - return $this->id->toString(); - } - public static function create(ProfileId $id, string $name): self { $self = new self(); diff --git a/tests/Integration/Pipeline/Aggregate/Profile.php b/tests/Integration/Pipeline/Aggregate/Profile.php index c7065ce5d..548bd9832 100644 --- a/tests/Integration/Pipeline/Aggregate/Profile.php +++ b/tests/Integration/Pipeline/Aggregate/Profile.php @@ -6,6 +6,7 @@ use Patchlevel\EventSourcing\Aggregate\BasicAggregateRoot; use Patchlevel\EventSourcing\Attribute\Aggregate; +use Patchlevel\EventSourcing\Attribute\AggregateId; use Patchlevel\EventSourcing\Attribute\Apply; use Patchlevel\EventSourcing\Tests\Integration\Pipeline\Events\NewVisited; use Patchlevel\EventSourcing\Tests\Integration\Pipeline\Events\OldVisited; @@ -16,15 +17,11 @@ #[Aggregate('profile')] final class Profile extends BasicAggregateRoot { + #[AggregateId] private ProfileId $id; private bool $privacy; private int $visited; - public function aggregateRootId(): string - { - return $this->id->toString(); - } - public static function create(ProfileId $id): self { $self = new self(); diff --git a/tests/Integration/Projectionist/Aggregate/Profile.php b/tests/Integration/Projectionist/Aggregate/Profile.php index 8f1f7c39f..e24f6c64a 100644 --- a/tests/Integration/Projectionist/Aggregate/Profile.php +++ b/tests/Integration/Projectionist/Aggregate/Profile.php @@ -6,6 +6,7 @@ use Patchlevel\EventSourcing\Aggregate\BasicAggregateRoot; use Patchlevel\EventSourcing\Attribute\Aggregate; +use Patchlevel\EventSourcing\Attribute\AggregateId; use Patchlevel\EventSourcing\Attribute\Apply; use Patchlevel\EventSourcing\Tests\Integration\Projectionist\Events\ProfileCreated; use Patchlevel\EventSourcing\Tests\Integration\Projectionist\Normalizer\ProfileIdNormalizer; @@ -14,15 +15,11 @@ #[Aggregate('profile')] final class Profile extends BasicAggregateRoot { + #[AggregateId] #[ProfileIdNormalizer] private ProfileId $id; private string $name; - public function aggregateRootId(): string - { - return $this->id->toString(); - } - public static function create(ProfileId $id, string $name): self { $self = new self(); diff --git a/tests/Integration/Store/Profile.php b/tests/Integration/Store/Profile.php index 76bdea122..e1bc7e8bd 100644 --- a/tests/Integration/Store/Profile.php +++ b/tests/Integration/Store/Profile.php @@ -6,6 +6,7 @@ use Patchlevel\EventSourcing\Aggregate\BasicAggregateRoot; use Patchlevel\EventSourcing\Attribute\Aggregate; +use Patchlevel\EventSourcing\Attribute\AggregateId; use Patchlevel\EventSourcing\Attribute\Apply; use Patchlevel\EventSourcing\Tests\Integration\Projectionist\Events\ProfileCreated; use Patchlevel\EventSourcing\Tests\Integration\Projectionist\Normalizer\ProfileIdNormalizer; @@ -14,15 +15,11 @@ #[Aggregate('profile')] final class Profile extends BasicAggregateRoot { + #[AggregateId] #[ProfileIdNormalizer] private ProfileId $id; private string $name; - public function aggregateRootId(): string - { - return $this->id->toString(); - } - public static function create(ProfileId $id, string $name): self { $self = new self(); diff --git a/tests/Unit/Fixture/Profile.php b/tests/Unit/Fixture/Profile.php index 40e5a8335..f72166627 100644 --- a/tests/Unit/Fixture/Profile.php +++ b/tests/Unit/Fixture/Profile.php @@ -6,6 +6,7 @@ use Patchlevel\EventSourcing\Aggregate\BasicAggregateRoot; use Patchlevel\EventSourcing\Attribute\Aggregate; +use Patchlevel\EventSourcing\Attribute\AggregateId; use Patchlevel\EventSourcing\Attribute\Apply; use Patchlevel\EventSourcing\Attribute\SuppressMissingApply; @@ -13,6 +14,7 @@ #[SuppressMissingApply([MessageDeleted::class])] final class Profile extends BasicAggregateRoot { + #[AggregateId] private ProfileId $id; private Email $email; private int $visits = 0; @@ -89,9 +91,4 @@ protected function applySplittingEvent(SplittingEvent $event): void $this->email = $event->email; $this->visits = $event->visits; } - - public function aggregateRootId(): string - { - return $this->id->toString(); - } } diff --git a/tests/Unit/Fixture/ProfileId.php b/tests/Unit/Fixture/ProfileId.php index 566e80f37..55fb67218 100644 --- a/tests/Unit/Fixture/ProfileId.php +++ b/tests/Unit/Fixture/ProfileId.php @@ -4,7 +4,9 @@ namespace Patchlevel\EventSourcing\Tests\Unit\Fixture; -final class ProfileId +use Patchlevel\EventSourcing\Aggregate\AggregateRootId; + +final class ProfileId implements AggregateRootId { private function __construct( private string $id, diff --git a/tests/Unit/Fixture/ProfileInvalid.php b/tests/Unit/Fixture/ProfileInvalid.php index b9e346240..b6815b9bf 100644 --- a/tests/Unit/Fixture/ProfileInvalid.php +++ b/tests/Unit/Fixture/ProfileInvalid.php @@ -6,11 +6,13 @@ use Patchlevel\EventSourcing\Aggregate\BasicAggregateRoot; use Patchlevel\EventSourcing\Attribute\Aggregate; +use Patchlevel\EventSourcing\Attribute\AggregateId; use Patchlevel\EventSourcing\Attribute\Apply; #[Aggregate(ProfileInvalid::class)] final class ProfileInvalid extends BasicAggregateRoot { + #[AggregateId] private ProfileId $id; private Email $email; @@ -35,9 +37,4 @@ protected function applyProfileCreated2(ProfileCreated $event): void $this->id = $event->profileId; $this->email = $event->email; } - - public function aggregateRootId(): string - { - return $this->id->toString(); - } } diff --git a/tests/Unit/Fixture/ProfileWithBrokenApplyBothUsage.php b/tests/Unit/Fixture/ProfileWithBrokenApplyBothUsage.php index 7f323882d..86fb2da68 100644 --- a/tests/Unit/Fixture/ProfileWithBrokenApplyBothUsage.php +++ b/tests/Unit/Fixture/ProfileWithBrokenApplyBothUsage.php @@ -16,9 +16,4 @@ final class ProfileWithBrokenApplyBothUsage extends BasicAggregateRoot protected function applyProfileCreated(ProfileCreated|ProfileVisited $event): void { } - - public function aggregateRootId(): string - { - return self::class; - } } diff --git a/tests/Unit/Fixture/ProfileWithBrokenApplyIntersection.php b/tests/Unit/Fixture/ProfileWithBrokenApplyIntersection.php index cbd6e2c41..b52984956 100644 --- a/tests/Unit/Fixture/ProfileWithBrokenApplyIntersection.php +++ b/tests/Unit/Fixture/ProfileWithBrokenApplyIntersection.php @@ -15,9 +15,4 @@ final class ProfileWithBrokenApplyIntersection extends BasicAggregateRoot protected function applyIntersection(ProfileCreated&ProfileVisited $event): void { } - - public function aggregateRootId(): string - { - return self::class; - } } diff --git a/tests/Unit/Fixture/ProfileWithBrokenApplyMultipleApply.php b/tests/Unit/Fixture/ProfileWithBrokenApplyMultipleApply.php index 50487d828..f1ad7158e 100644 --- a/tests/Unit/Fixture/ProfileWithBrokenApplyMultipleApply.php +++ b/tests/Unit/Fixture/ProfileWithBrokenApplyMultipleApply.php @@ -16,9 +16,4 @@ final class ProfileWithBrokenApplyMultipleApply extends BasicAggregateRoot protected function applyNameChanged(NameChanged $event): void { } - - public function aggregateRootId(): string - { - return self::class; - } } diff --git a/tests/Unit/Fixture/ProfileWithBrokenApplyNoType.php b/tests/Unit/Fixture/ProfileWithBrokenApplyNoType.php index 2720574d6..e64380cdc 100644 --- a/tests/Unit/Fixture/ProfileWithBrokenApplyNoType.php +++ b/tests/Unit/Fixture/ProfileWithBrokenApplyNoType.php @@ -16,9 +16,4 @@ final class ProfileWithBrokenApplyNoType extends BasicAggregateRoot protected function applyWithNoType($event): void { } - - public function aggregateRootId(): string - { - return self::class; - } } diff --git a/tests/Unit/Fixture/ProfileWithEmptyApply.php b/tests/Unit/Fixture/ProfileWithEmptyApply.php index f3ffb8e9b..332bb6da1 100644 --- a/tests/Unit/Fixture/ProfileWithEmptyApply.php +++ b/tests/Unit/Fixture/ProfileWithEmptyApply.php @@ -20,9 +20,4 @@ protected function applyProfileCreated(ProfileCreated|ProfileVisited $event): vo protected function applyNameChanged(NameChanged $event): void { } - - public function aggregateRootId(): string - { - return self::class; - } } diff --git a/tests/Unit/Fixture/ProfileWithSnapshot.php b/tests/Unit/Fixture/ProfileWithSnapshot.php index abb9606c7..1cc956aba 100644 --- a/tests/Unit/Fixture/ProfileWithSnapshot.php +++ b/tests/Unit/Fixture/ProfileWithSnapshot.php @@ -6,6 +6,7 @@ use Patchlevel\EventSourcing\Aggregate\BasicAggregateRoot; use Patchlevel\EventSourcing\Attribute\Aggregate; +use Patchlevel\EventSourcing\Attribute\AggregateId; use Patchlevel\EventSourcing\Attribute\Apply; use Patchlevel\EventSourcing\Attribute\Snapshot; use Patchlevel\EventSourcing\Attribute\SuppressMissingApply; @@ -17,6 +18,7 @@ final class ProfileWithSnapshot extends BasicAggregateRoot { #[ProfileIdNormalizer] + #[AggregateId] private ProfileId $id; #[EmailNormalizer] private Email $email; @@ -73,9 +75,4 @@ protected function applyMessagePublished(MessagePublished $event): void { $this->messages[] = $event->message; } - - public function aggregateRootId(): string - { - return $this->id->toString(); - } } diff --git a/tests/Unit/Fixture/ProfileWithSuppressAll.php b/tests/Unit/Fixture/ProfileWithSuppressAll.php index 7800ab121..14ee63bf1 100644 --- a/tests/Unit/Fixture/ProfileWithSuppressAll.php +++ b/tests/Unit/Fixture/ProfileWithSuppressAll.php @@ -19,9 +19,4 @@ public static function createProfile(ProfileId $id, Email $email): self return $self; } - - public function aggregateRootId(): string - { - return '1'; - } } diff --git a/tests/Unit/Fixture/WrongNormalizerBasicAggregate.php b/tests/Unit/Fixture/WrongNormalizerBasicAggregate.php index 232e8e0e9..39505fead 100644 --- a/tests/Unit/Fixture/WrongNormalizerBasicAggregate.php +++ b/tests/Unit/Fixture/WrongNormalizerBasicAggregate.php @@ -12,9 +12,4 @@ final class WrongNormalizerBasicAggregate extends BasicAggregateRoot { #[EmailNormalizer] public bool $email = true; - - public function aggregateRootId(): string - { - return '1'; - } } diff --git a/tests/Unit/Repository/DefaultRepositoryTest.php b/tests/Unit/Repository/DefaultRepositoryTest.php index fe3d8ad39..fdab86b19 100644 --- a/tests/Unit/Repository/DefaultRepositoryTest.php +++ b/tests/Unit/Repository/DefaultRepositoryTest.php @@ -527,7 +527,7 @@ public function testLoadAggregate(): void Profile::metadata(), ); - $aggregate = $repository->load('1'); + $aggregate = $repository->load(ProfileId::fromString('1')); self::assertInstanceOf(Profile::class, $aggregate); self::assertSame(1, $aggregate->playhead()); @@ -568,8 +568,8 @@ public function testLoadAggregateTwice(): void Profile::metadata(), ); - $aggregate1 = $repository->load('1'); - $aggregate2 = $repository->load('1'); + $aggregate1 = $repository->load(ProfileId::fromString('1')); + $aggregate2 = $repository->load(ProfileId::fromString('1')); self::assertEquals($aggregate1, $aggregate2); self::assertNotSame($aggregate1, $aggregate2); @@ -593,7 +593,7 @@ public function testAggregateNotFound(): void Profile::metadata(), ); - $repository->load('1'); + $repository->load(ProfileId::fromString('1')); } public function testHasAggregate(): void @@ -612,7 +612,7 @@ public function testHasAggregate(): void Profile::metadata(), ); - self::assertTrue($repository->has('1')); + self::assertTrue($repository->has(ProfileId::fromString('1'))); } public function testNotHasAggregate(): void @@ -631,7 +631,7 @@ public function testNotHasAggregate(): void Profile::metadata(), ); - self::assertFalse($repository->has('1')); + self::assertFalse($repository->has(ProfileId::fromString('1'))); } public function testLoadAggregateWithSnapshot(): void @@ -664,7 +664,7 @@ public function testLoadAggregateWithSnapshot(): void $snapshotStore->reveal(), ); - $aggregate = $repository->load('1'); + $aggregate = $repository->load(ProfileId::fromString('1')); self::assertInstanceOf(ProfileWithSnapshot::class, $aggregate); self::assertSame(1, $aggregate->playhead()); @@ -718,7 +718,7 @@ public function testLoadAggregateWithSnapshotFirstTime(): void $snapshotStore->reveal(), ); - $aggregate = $repository->load('1'); + $aggregate = $repository->load(ProfileId::fromString('1')); self::assertInstanceOf(ProfileWithSnapshot::class, $aggregate); self::assertSame(3, $aggregate->playhead()); @@ -764,7 +764,7 @@ public function testLoadAggregateWithSnapshotAndSaveNewVersion(): void $snapshotStore = $this->prophesize(SnapshotStore::class); $snapshotStore->load( ProfileWithSnapshot::class, - '1', + ProfileId::fromString('1'), )->willReturn($profile); $snapshotStore->save($profile)->shouldBeCalled(); @@ -776,7 +776,7 @@ public function testLoadAggregateWithSnapshotAndSaveNewVersion(): void $snapshotStore->reveal(), ); - $aggregate = $repository->load('1'); + $aggregate = $repository->load(ProfileId::fromString('1')); self::assertInstanceOf(ProfileWithSnapshot::class, $aggregate); self::assertSame(4, $aggregate->playhead()); @@ -800,7 +800,7 @@ public function testLoadAggregateWithoutSnapshot(): void $eventBus = $this->prophesize(EventBus::class); $snapshotStore = $this->prophesize(SnapshotStore::class); - $snapshotStore->load(ProfileWithSnapshot::class, '1') + $snapshotStore->load(ProfileWithSnapshot::class, ProfileId::fromString('1')) ->willThrow(SnapshotNotFound::class); $repository = new DefaultRepository( @@ -810,7 +810,7 @@ public function testLoadAggregateWithoutSnapshot(): void $snapshotStore->reveal(), ); - $aggregate = $repository->load('1'); + $aggregate = $repository->load(ProfileId::fromString('1')); self::assertInstanceOf(ProfileWithSnapshot::class, $aggregate); self::assertSame(1, $aggregate->playhead());