diff --git a/README.md b/README.md index a7ae32823..d73cb69e0 100644 --- a/README.md +++ b/README.md @@ -96,13 +96,16 @@ use App\Domain\Profile\Email; use App\Domain\Profile\ProfileId; use Patchlevel\EventSourcing\Aggregate\AggregateChanged; +/** + * @template-extends AggregateChanged + */ final class ProfileCreated extends AggregateChanged { public static function raise( ProfileId $id, Email $email ): AggregateChanged { - return self::occur( + return new self( $id->toString(), [ 'profileId' => $id->toString(), diff --git a/baseline.xml b/baseline.xml index 7e86b12db..495bd4d74 100644 --- a/baseline.xml +++ b/baseline.xml @@ -1,13 +1,15 @@ + + + $callable + + $payload - - - @@ -30,21 +32,6 @@ $text - - - $this->payload['message'] - - - - - $this->payload['email'] - - - - - $this->payload['visitorId'] - - SnapshotableAggregateRoot @@ -53,9 +40,6 @@ $payload - - - diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 9c96c4092..590e93114 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -13,6 +13,9 @@ + + + diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index a04f229d5..16239a0d2 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,12 +1,97 @@ parameters: ignoreErrors: + - + message: "#^Method Patchlevel\\\\EventSourcing\\\\Aggregate\\\\AggregateChanged\\:\\:serialize\\(\\) return type with generic class Patchlevel\\\\EventSourcing\\\\Aggregate\\\\AggregateChanged does not specify its types\\: T$#" + count: 1 + path: src/Aggregate/AggregateChanged.php + + - + message: "#^Method Patchlevel\\\\EventSourcing\\\\Aggregate\\\\AggregateRoot\\:\\:apply\\(\\) has parameter \\$event with generic class Patchlevel\\\\EventSourcing\\\\Aggregate\\\\AggregateChanged but does not specify its types\\: T$#" + count: 1 + path: src/Aggregate/AggregateRoot.php + + - + message: "#^Method Patchlevel\\\\EventSourcing\\\\Aggregate\\\\AggregateRoot\\:\\:createFromEventStream\\(\\) has parameter \\$stream with generic class Patchlevel\\\\EventSourcing\\\\Aggregate\\\\AggregateChanged but does not specify its types\\: T$#" + count: 1 + path: src/Aggregate/AggregateRoot.php + + - + message: "#^Method Patchlevel\\\\EventSourcing\\\\Aggregate\\\\AggregateRoot\\:\\:releaseEvents\\(\\) return type with generic class Patchlevel\\\\EventSourcing\\\\Aggregate\\\\AggregateChanged does not specify its types\\: T$#" + count: 1 + path: src/Aggregate/AggregateRoot.php + + - + message: "#^Property Patchlevel\\\\EventSourcing\\\\Aggregate\\\\AggregateRoot\\:\\:\\$uncommittedEvents with generic class Patchlevel\\\\EventSourcing\\\\Aggregate\\\\AggregateChanged does not specify its types\\: T$#" + count: 1 + path: src/Aggregate/AggregateRoot.php + + - + message: "#^Method Patchlevel\\\\EventSourcing\\\\Aggregate\\\\ApplyMethodNotFound\\:\\:__construct\\(\\) has parameter \\$event with generic class Patchlevel\\\\EventSourcing\\\\Aggregate\\\\AggregateChanged but does not specify its types\\: T$#" + count: 1 + path: src/Aggregate/ApplyMethodNotFound.php + - message: "#^Method Patchlevel\\\\EventSourcing\\\\Console\\\\DoctrineHelper\\:\\:databaseName\\(\\) should return string but returns mixed\\.$#" count: 2 path: src/Console/DoctrineHelper.php + - + message: "#^Method Patchlevel\\\\EventSourcing\\\\Console\\\\EventPrinter\\:\\:write\\(\\) has parameter \\$event with generic class Patchlevel\\\\EventSourcing\\\\Aggregate\\\\AggregateChanged but does not specify its types\\: T$#" + count: 1 + path: src/Console/EventPrinter.php + + - + message: "#^Method Patchlevel\\\\EventSourcing\\\\Pipeline\\\\Middleware\\\\ExcludeEventMiddleware\\:\\:__construct\\(\\) has parameter \\$classes with generic class Patchlevel\\\\EventSourcing\\\\Aggregate\\\\AggregateChanged but does not specify its types\\: T$#" + count: 1 + path: src/Pipeline/Middleware/ExcludeEventMiddleware.php + + - + message: "#^Property Patchlevel\\\\EventSourcing\\\\Pipeline\\\\Middleware\\\\ExcludeEventMiddleware\\:\\:\\$classes with generic class Patchlevel\\\\EventSourcing\\\\Aggregate\\\\AggregateChanged does not specify its types\\: T$#" + count: 1 + path: src/Pipeline/Middleware/ExcludeEventMiddleware.php + + - + message: "#^Method Patchlevel\\\\EventSourcing\\\\Pipeline\\\\Middleware\\\\FilterEventMiddleware\\:\\:__construct\\(\\) has parameter \\$callable with generic class Patchlevel\\\\EventSourcing\\\\Aggregate\\\\AggregateChanged but does not specify its types\\: T$#" + count: 1 + path: src/Pipeline/Middleware/FilterEventMiddleware.php + + - + message: "#^Property Patchlevel\\\\EventSourcing\\\\Pipeline\\\\Middleware\\\\FilterEventMiddleware\\:\\:\\$callable with generic class Patchlevel\\\\EventSourcing\\\\Aggregate\\\\AggregateChanged does not specify its types\\: T$#" + count: 1 + path: src/Pipeline/Middleware/FilterEventMiddleware.php + + - + message: "#^Method Patchlevel\\\\EventSourcing\\\\Pipeline\\\\Middleware\\\\IncludeEventMiddleware\\:\\:__construct\\(\\) has parameter \\$classes with generic class Patchlevel\\\\EventSourcing\\\\Aggregate\\\\AggregateChanged but does not specify its types\\: T$#" + count: 1 + path: src/Pipeline/Middleware/IncludeEventMiddleware.php + + - + message: "#^Property Patchlevel\\\\EventSourcing\\\\Pipeline\\\\Middleware\\\\IncludeEventMiddleware\\:\\:\\$classes with generic class Patchlevel\\\\EventSourcing\\\\Aggregate\\\\AggregateChanged does not specify its types\\: T$#" + count: 1 + path: src/Pipeline/Middleware/IncludeEventMiddleware.php + + - + message: "#^Unable to resolve the template type E in call to method static method Patchlevel\\\\EventSourcing\\\\Aggregate\\\\AggregateChanged\\\\>\\:\\:deserialize\\(\\)$#" + count: 1 + path: src/Store/MultiTableStore.php + + - + message: "#^Unable to resolve the template type T in call to method static method Patchlevel\\\\EventSourcing\\\\Store\\\\DoctrineStore\\:\\:normalizeResult\\(\\)$#" + count: 1 + path: src/Store/MultiTableStore.php + + - + message: "#^Method Patchlevel\\\\EventSourcing\\\\WatchServer\\\\WatchServer\\:\\:listen\\(\\) has parameter \\$callback with generic class Patchlevel\\\\EventSourcing\\\\Aggregate\\\\AggregateChanged but does not specify its types\\: T$#" + count: 1 + path: src/WatchServer/WatchServer.php + - message: "#^While loop condition is always true\\.$#" count: 1 path: src/WatchServer/WatchServer.php + - + message: "#^Method Patchlevel\\\\EventSourcing\\\\WatchServer\\\\WatchServerClient\\:\\:send\\(\\) has parameter \\$event with generic class Patchlevel\\\\EventSourcing\\\\Aggregate\\\\AggregateChanged but does not specify its types\\: T$#" + count: 1 + path: src/WatchServer/WatchServerClient.php + diff --git a/src/Aggregate/AggregateChanged.php b/src/Aggregate/AggregateChanged.php index e8221d9c1..9c1a80425 100644 --- a/src/Aggregate/AggregateChanged.php +++ b/src/Aggregate/AggregateChanged.php @@ -11,19 +11,26 @@ use const JSON_THROW_ON_ERROR; +/** + * @template-covariant T of array + */ abstract class AggregateChanged { + /** @readonly */ protected string $aggregateId; - /** @var array */ + /** + * @readonly + * @var T + */ protected array $payload; private ?int $playhead; private ?DateTimeImmutable $recordedOn; /** - * @param array $payload + * @param T $payload */ - final private function __construct(string $aggregateId, array $payload = []) + final public function __construct(string $aggregateId, array $payload = []) { $this->aggregateId = $aggregateId; $this->payload = $payload; @@ -47,23 +54,13 @@ public function recordedOn(): ?DateTimeImmutable } /** - * @return array + * @return T */ public function payload(): array { return $this->payload; } - /** - * @param array $payload - * - * @return static - */ - protected static function occur(string $aggregateId, array $payload = []): self - { - return new static($aggregateId, $payload); - } - /** * @internal * @@ -75,6 +72,7 @@ public function recordNow(int $playhead): self throw new AggregateChangeRecordedAlready(); } + /** @psalm-suppress UnsafeGenericInstantiation */ $event = new static($this->aggregateId, $this->payload); $event->playhead = $playhead; $event->recordedOn = $this->createRecordDate(); @@ -83,7 +81,11 @@ public function recordNow(int $playhead): self } /** - * @param array{aggregateId: string, playhead: int, event: class-string, payload: string, recordedOn: DateTimeImmutable} $data + * @param array{aggregateId: string, playhead: int, event: class-string, payload: string, recordedOn: DateTimeImmutable} $data + * + * @return E + * + * @template E of self */ public static function deserialize(array $data): self { diff --git a/src/Aggregate/AggregateRoot.php b/src/Aggregate/AggregateRoot.php index ba3169817..dfebf8bf2 100644 --- a/src/Aggregate/AggregateRoot.php +++ b/src/Aggregate/AggregateRoot.php @@ -20,6 +20,9 @@ abstract public function aggregateRootId(): string; abstract protected function apply(AggregateChanged $event): void; + /** + * @param AggregateChanged> $event + */ protected function record(AggregateChanged $event): void { $this->playhead++; diff --git a/src/Aggregate/SnapshotableAggregateRoot.php b/src/Aggregate/SnapshotableAggregateRoot.php index 94827b8c9..567deeb09 100644 --- a/src/Aggregate/SnapshotableAggregateRoot.php +++ b/src/Aggregate/SnapshotableAggregateRoot.php @@ -21,7 +21,7 @@ abstract protected function serialize(): array; abstract protected static function deserialize(array $payload): self; /** - * @param array $stream + * @param array>> $stream * * @return static */ diff --git a/src/EventBus/DefaultEventBus.php b/src/EventBus/DefaultEventBus.php index 78745edcc..90e273d77 100644 --- a/src/EventBus/DefaultEventBus.php +++ b/src/EventBus/DefaultEventBus.php @@ -10,7 +10,7 @@ final class DefaultEventBus implements EventBus { - /** @var list */ + /** @var list>> */ private array $queue; /** @var list */ private array $listeners; @@ -27,6 +27,9 @@ public function __construct(array $listeners = []) $this->processing = false; } + /** + * @param AggregateChanged> $event + */ public function dispatch(AggregateChanged $event): void { $this->queue[] = $event; diff --git a/src/EventBus/EventBus.php b/src/EventBus/EventBus.php index 5c5db4882..8221e6dd9 100644 --- a/src/EventBus/EventBus.php +++ b/src/EventBus/EventBus.php @@ -8,5 +8,8 @@ interface EventBus { + /** + * @param AggregateChanged> $event + */ public function dispatch(AggregateChanged $event): void; } diff --git a/src/EventBus/Listener.php b/src/EventBus/Listener.php index 58c79d3a1..69280f42d 100644 --- a/src/EventBus/Listener.php +++ b/src/EventBus/Listener.php @@ -8,5 +8,8 @@ interface Listener { + /** + * @param AggregateChanged> $event + */ public function __invoke(AggregateChanged $event): void; } diff --git a/src/EventBus/SymfonyEventBus.php b/src/EventBus/SymfonyEventBus.php index 49aef9297..8ed7a177d 100644 --- a/src/EventBus/SymfonyEventBus.php +++ b/src/EventBus/SymfonyEventBus.php @@ -21,6 +21,9 @@ public function __construct(MessageBusInterface $bus) $this->bus = $bus; } + /** + * @param AggregateChanged> $event + */ public function dispatch(AggregateChanged $event): void { $envelope = (new Envelope($event)) diff --git a/src/Pipeline/EventBucket.php b/src/Pipeline/EventBucket.php index 11c030ce0..22622394c 100644 --- a/src/Pipeline/EventBucket.php +++ b/src/Pipeline/EventBucket.php @@ -12,10 +12,13 @@ class EventBucket /** @var class-string */ private string $aggregateClass; private int $index; + + /** @var AggregateChanged> */ private AggregateChanged $event; /** - * @param class-string $aggregateClass + * @param class-string $aggregateClass + * @param AggregateChanged> $event */ public function __construct(string $aggregateClass, int $index, AggregateChanged $event) { @@ -37,6 +40,9 @@ public function index(): int return $this->index; } + /** + * @return AggregateChanged> + */ public function event(): AggregateChanged { return $this->event; diff --git a/src/Pipeline/Middleware/ClassRenameMiddleware.php b/src/Pipeline/Middleware/ClassRenameMiddleware.php index 5bb937e69..7c44d05f5 100644 --- a/src/Pipeline/Middleware/ClassRenameMiddleware.php +++ b/src/Pipeline/Middleware/ClassRenameMiddleware.php @@ -12,11 +12,11 @@ class ClassRenameMiddleware implements Middleware { - /** @var array, class-string> */ + /** @var array>>, class-string>>> */ private array $classes; /** - * @param array, class-string> $classes + * @param array>>, class-string>>> $classes */ public function __construct(array $classes) { diff --git a/src/Pipeline/Middleware/ReplaceEventMiddleware.php b/src/Pipeline/Middleware/ReplaceEventMiddleware.php index bf2f5f941..fd1441395 100644 --- a/src/Pipeline/Middleware/ReplaceEventMiddleware.php +++ b/src/Pipeline/Middleware/ReplaceEventMiddleware.php @@ -9,20 +9,23 @@ use ReflectionClass; use ReflectionProperty; +/** + * @template T of AggregateChanged + */ class ReplaceEventMiddleware implements Middleware { - /** @var class-string */ + /** @var class-string */ private string $class; - /** @var callable(AggregateChanged $event):AggregateChanged */ + /** @var callable(T $event):AggregateChanged> */ private $callable; private ReflectionProperty $recoredOnProperty; private ReflectionProperty $playheadProperty; /** - * @param class-string $class - * @param callable(AggregateChanged $event):AggregateChanged $callable + * @param class-string $class + * @param callable(T $event):AggregateChanged> $callable */ public function __construct(string $class, callable $callable) { diff --git a/src/Projection/DefaultProjectionRepository.php b/src/Projection/DefaultProjectionRepository.php index 2cb1f2935..23185bb27 100644 --- a/src/Projection/DefaultProjectionRepository.php +++ b/src/Projection/DefaultProjectionRepository.php @@ -28,6 +28,7 @@ public function handle(AggregateChanged $event): void $handlers = $projection->handledEvents(); foreach ($handlers as $class => $method) { + /** @psalm-suppress DocblockTypeContradiction */ if (!$event instanceof $class) { continue; } diff --git a/src/Projection/Projection.php b/src/Projection/Projection.php index 2e623ce0e..fa09e0a59 100644 --- a/src/Projection/Projection.php +++ b/src/Projection/Projection.php @@ -8,7 +8,7 @@ interface Projection { - /** @return iterable, string> */ + /** @return iterable>>, string> */ public function handledEvents(): iterable; public function create(): void; diff --git a/src/Projection/ProjectionRepository.php b/src/Projection/ProjectionRepository.php index 45a96e7d9..e5e7995a3 100644 --- a/src/Projection/ProjectionRepository.php +++ b/src/Projection/ProjectionRepository.php @@ -8,6 +8,9 @@ interface ProjectionRepository { + /** + * @param AggregateChanged> $event + */ public function handle(AggregateChanged $event): void; public function create(): void; diff --git a/src/Store/CorruptedMetadata.php b/src/Store/CorruptedMetadata.php index befaaed7f..57a94287d 100644 --- a/src/Store/CorruptedMetadata.php +++ b/src/Store/CorruptedMetadata.php @@ -8,12 +8,20 @@ final class CorruptedMetadata extends StoreException { - public function __construct(string $expectedId, string $actualId) + public static function fromEntryMismatch(string $expectedId, string $actualId): self { - parent::__construct(sprintf( + return new self(sprintf( 'Corrupted metadata: expected id is %s get %s', $expectedId, $actualId )); } + + public static function fromMissingEntry(string $expectedId): self + { + return new self(sprintf( + 'Corrupted metadata: expected id is %s there but it is missing', + $expectedId + )); + } } diff --git a/src/Store/DoctrineStore.php b/src/Store/DoctrineStore.php index e3a7b1e9b..850ff88fe 100644 --- a/src/Store/DoctrineStore.php +++ b/src/Store/DoctrineStore.php @@ -10,7 +10,6 @@ use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Types; -use Patchlevel\EventSourcing\Aggregate\AggregateChanged; use function is_int; @@ -31,9 +30,11 @@ public function connection(): Connection abstract public function schema(): Schema; /** - * @param array{aggregateId: string, playhead: string, event: class-string, payload: string, recordedOn: string} $result + * @param array{aggregateId: string, playhead: string, event: class-string, payload: string, recordedOn: string} $result * - * @return array{aggregateId: string, playhead: int, event: class-string, payload: string, recordedOn: DateTimeImmutable} + * @return array{aggregateId: string, playhead: int, event: class-string, payload: string, recordedOn: DateTimeImmutable} + * + * @template T */ protected static function normalizeResult(AbstractPlatform $platform, array $result): array { diff --git a/src/Store/MultiTableStore.php b/src/Store/MultiTableStore.php index 70c6d89fb..2440bcf17 100644 --- a/src/Store/MultiTableStore.php +++ b/src/Store/MultiTableStore.php @@ -42,7 +42,7 @@ public function __construct( /** * @param class-string $aggregate * - * @return array + * @return array>> */ public function load(string $aggregate, string $id, int $fromPlayhead = 0): array { @@ -54,7 +54,7 @@ public function load(string $aggregate, string $id, int $fromPlayhead = 0): arra ->where('aggregateId = :id AND playhead > :playhead') ->getSQL(); - /** @var array, payload: string, recordedOn: string}> $result */ + /** @var array>>, payload: string, recordedOn: string}> $result */ $result = $this->connection->fetchAllAssociative( $sql, [ @@ -102,8 +102,8 @@ public function has(string $aggregate, string $id): bool } /** - * @param class-string $aggregate - * @param array $events + * @param class-string $aggregate + * @param array>> $events */ public function saveBatch(string $aggregate, string $id, array $events): void { @@ -138,7 +138,9 @@ public function stream(int $fromIndex = 0): Generator ->orderBy('id') ->getSQL(); - /** @var Traversable, payload: string, recordedOn: string}> $query */ + /** + * @var Traversable>>, payload: string, recordedOn: string}> $query + */ $query = $this->connection->iterateAssociative($sql, ['index' => $fromIndex]); if (!$query instanceof Generator) { @@ -155,7 +157,9 @@ public function stream(int $fromIndex = 0): Generator ->orderBy('id') ->getSQL(); - /** @var Traversable}> $metaQuery */ + /** + * @var Traversable $metaQuery + */ $metaQuery = $this->connection->iterateAssociative($sql, ['index' => $fromIndex]); $platform = $this->connection->getDatabasePlatform(); @@ -169,10 +173,15 @@ public function stream(int $fromIndex = 0): Generator } $eventData = $queries[$name]->current(); + + if ($eventData === null) { + throw CorruptedMetadata::fromMissingEntry($metaData['id']); + } + $queries[$name]->next(); if ($eventData['id'] !== $metaData['id']) { - throw new CorruptedMetadata($metaData['id'], $eventData['id']); + throw CorruptedMetadata::fromEntryMismatch($metaData['id'], $eventData['id']); } yield new EventBucket( @@ -211,14 +220,17 @@ public function saveEventBucket(EventBucket $bucket): void ); } - private function saveEvent(Connection $connection, string $aggregate, AggregateChanged $event): void + /** + * @param AggregateChanged> $event + */ + private function saveEvent(Connection $connection, string $aggregateName, AggregateChanged $event): void { $data = $event->serialize(); $connection->insert( $this->metadataTableName, [ - 'aggregate' => $aggregate, + 'aggregate' => $aggregateName, 'aggregateId' => $data['aggregateId'], 'playhead' => $data['playhead'], ], @@ -227,7 +239,7 @@ private function saveEvent(Connection $connection, string $aggregate, AggregateC $data['id'] = (int)$connection->lastInsertId(); $connection->insert( - $aggregate, + $aggregateName, $data, [ 'recordedOn' => Types::DATETIMETZ_IMMUTABLE, diff --git a/src/Store/SingleTableStore.php b/src/Store/SingleTableStore.php index 0c593e219..a41b80496 100644 --- a/src/Store/SingleTableStore.php +++ b/src/Store/SingleTableStore.php @@ -38,7 +38,7 @@ public function __construct(Connection $connection, array $aggregates, string $s /** * @param class-string $aggregate * - * @return array + * @return array>> */ public function load(string $aggregate, string $id, int $fromPlayhead = 0): array { @@ -50,7 +50,7 @@ public function load(string $aggregate, string $id, int $fromPlayhead = 0): arra ->where('aggregate = :aggregate AND aggregateId = :id AND playhead > :playhead') ->getSQL(); - /** @var array, payload: string, recordedOn: string}> $result */ + /** @var array>>, payload: string, recordedOn: string}> $result */ $result = $this->connection->fetchAllAssociative( $sql, [ @@ -102,8 +102,8 @@ public function has(string $aggregate, string $id): bool } /** - * @param class-string $aggregate - * @param array $events + * @param class-string $aggregate + * @param array>> $events */ public function saveBatch(string $aggregate, string $id, array $events): void { @@ -144,7 +144,17 @@ public function stream(int $fromIndex = 0): Generator ->orderBy('id') ->getSQL(); - /** @var array, payload: string, recordedOn: string}> $result */ + /** + * @var array>>, + * payload: string, + * recordedOn: string + * }> $result + */ $result = $this->connection->iterateAssociative($sql, ['index' => $fromIndex]); $platform = $this->connection->getDatabasePlatform(); diff --git a/src/Store/Store.php b/src/Store/Store.php index 147c9b25b..219d4a056 100644 --- a/src/Store/Store.php +++ b/src/Store/Store.php @@ -12,7 +12,7 @@ interface Store /** * @param class-string $aggregate * - * @return array + * @return array>> */ public function load(string $aggregate, string $id, int $fromPlayhead = 0): array; @@ -22,8 +22,8 @@ public function load(string $aggregate, string $id, int $fromPlayhead = 0): arra public function has(string $aggregate, string $id): bool; /** - * @param class-string $aggregate - * @param array $events + * @param class-string $aggregate + * @param array>> $events */ public function saveBatch(string $aggregate, string $id, array $events): void; } diff --git a/src/WatchServer/WatchServer.php b/src/WatchServer/WatchServer.php index b68615ee1..3a6c30ac2 100644 --- a/src/WatchServer/WatchServer.php +++ b/src/WatchServer/WatchServer.php @@ -66,7 +66,7 @@ public function listen(callable $callback): void foreach ($this->messages($socket) as $clientId => $message) { $this->logger->info('Received a payload from client {clientId}', ['clientId' => $clientId]); - /** @var array{aggregateId: string, event: class-string, payload: string, playhead: int, recordedOn: DateTimeImmutable} $payload */ + /** @var array{aggregateId: string, event: class-string>>, payload: string, playhead: int, recordedOn: DateTimeImmutable} $payload */ $payload = unserialize(base64_decode($message), ['allowed_classes' => [DateTimeImmutable::class]]); $event = AggregateChanged::deserialize($payload); diff --git a/tests/Integration/BasicImplementation/Events/ProfileCreated.php b/tests/Integration/BasicImplementation/Events/ProfileCreated.php index c5021c3ad..63d597c5a 100644 --- a/tests/Integration/BasicImplementation/Events/ProfileCreated.php +++ b/tests/Integration/BasicImplementation/Events/ProfileCreated.php @@ -6,11 +6,14 @@ use Patchlevel\EventSourcing\Aggregate\AggregateChanged; +/** + * @template-extends AggregateChanged + */ final class ProfileCreated extends AggregateChanged { - public static function raise(string $id): AggregateChanged + public static function raise(string $id): self { - return self::occur($id, ['id' => $id]); + return new self($id, ['id' => $id]); } public function profileId(): string diff --git a/tests/Integration/BasicImplementation/Projection/ProfileProjection.php b/tests/Integration/BasicImplementation/Projection/ProfileProjection.php index 13dcc835d..9a7baaba4 100644 --- a/tests/Integration/BasicImplementation/Projection/ProfileProjection.php +++ b/tests/Integration/BasicImplementation/Projection/ProfileProjection.php @@ -5,7 +5,6 @@ namespace Patchlevel\EventSourcing\Tests\Integration\BasicImplementation\Projection; use Doctrine\DBAL\Connection; -use Patchlevel\EventSourcing\Aggregate\AggregateChanged; use Patchlevel\EventSourcing\Projection\Projection; use Patchlevel\EventSourcing\Tests\Integration\BasicImplementation\Events\ProfileCreated; @@ -18,7 +17,6 @@ public function __construct(Connection $connection) $this->connection = $connection; } - /** @return iterable, string> */ public function handledEvents(): iterable { yield ProfileCreated::class => 'applyProfileCreated'; diff --git a/tests/Integration/Pipeline/Events/NewVisited.php b/tests/Integration/Pipeline/Events/NewVisited.php index 57836d9f8..b487a7ca1 100644 --- a/tests/Integration/Pipeline/Events/NewVisited.php +++ b/tests/Integration/Pipeline/Events/NewVisited.php @@ -6,11 +6,14 @@ use Patchlevel\EventSourcing\Aggregate\AggregateChanged; +/** + * @template-extends AggregateChanged + */ final class NewVisited extends AggregateChanged { - public static function raise(string $id): AggregateChanged + public static function raise(string $id): self { - return self::occur($id, ['id' => $id]); + return new self($id, ['id' => $id]); } public function profileId(): string diff --git a/tests/Integration/Pipeline/Events/OldVisited.php b/tests/Integration/Pipeline/Events/OldVisited.php index ce002fa43..f51f0fc80 100644 --- a/tests/Integration/Pipeline/Events/OldVisited.php +++ b/tests/Integration/Pipeline/Events/OldVisited.php @@ -6,11 +6,14 @@ use Patchlevel\EventSourcing\Aggregate\AggregateChanged; +/** + * @template-extends AggregateChanged + */ final class OldVisited extends AggregateChanged { - public static function raise(string $id): AggregateChanged + public static function raise(string $id): self { - return self::occur($id, ['id' => $id]); + return new self($id, ['id' => $id]); } public function profileId(): string diff --git a/tests/Integration/Pipeline/Events/PrivacyAdded.php b/tests/Integration/Pipeline/Events/PrivacyAdded.php index b2cc9cdb0..c14d08dd7 100644 --- a/tests/Integration/Pipeline/Events/PrivacyAdded.php +++ b/tests/Integration/Pipeline/Events/PrivacyAdded.php @@ -6,11 +6,14 @@ use Patchlevel\EventSourcing\Aggregate\AggregateChanged; +/** + * @template-extends AggregateChanged + */ final class PrivacyAdded extends AggregateChanged { - public static function raise(string $id): AggregateChanged + public static function raise(string $id): self { - return self::occur($id, ['id' => $id]); + return new self($id, ['id' => $id]); } public function profileId(): string diff --git a/tests/Integration/Pipeline/Events/ProfileCreated.php b/tests/Integration/Pipeline/Events/ProfileCreated.php index 8dc093d0b..316d32b4d 100644 --- a/tests/Integration/Pipeline/Events/ProfileCreated.php +++ b/tests/Integration/Pipeline/Events/ProfileCreated.php @@ -6,11 +6,14 @@ use Patchlevel\EventSourcing\Aggregate\AggregateChanged; +/** + * @template-extends AggregateChanged + */ final class ProfileCreated extends AggregateChanged { - public static function raise(string $id): AggregateChanged + public static function raise(string $id): self { - return self::occur($id, ['id' => $id]); + return new self($id, ['id' => $id]); } public function profileId(): string diff --git a/tests/Unit/Fixture/MessagePublished.php b/tests/Unit/Fixture/MessagePublished.php index 901e8ab57..0c0ffb336 100644 --- a/tests/Unit/Fixture/MessagePublished.php +++ b/tests/Unit/Fixture/MessagePublished.php @@ -6,13 +6,16 @@ use Patchlevel\EventSourcing\Aggregate\AggregateChanged; +/** + * @template-extends AggregateChanged + */ final class MessagePublished extends AggregateChanged { public static function raise( ProfileId $id, Message $message ): self { - return self::occur( + return new self( $id->toString(), [ 'message' => $message->toArray(), diff --git a/tests/Unit/Fixture/ProfileCreated.php b/tests/Unit/Fixture/ProfileCreated.php index 980379471..e76c7f101 100644 --- a/tests/Unit/Fixture/ProfileCreated.php +++ b/tests/Unit/Fixture/ProfileCreated.php @@ -6,13 +6,16 @@ use Patchlevel\EventSourcing\Aggregate\AggregateChanged; +/** + * @template-extends AggregateChanged + */ class ProfileCreated extends AggregateChanged { public static function raise( ProfileId $id, Email $email ): self { - return self::occur( + return new self( $id->toString(), [ 'profileId' => $id->toString(), diff --git a/tests/Unit/Fixture/ProfileVisited.php b/tests/Unit/Fixture/ProfileVisited.php index 4e676ef77..bb30c2708 100644 --- a/tests/Unit/Fixture/ProfileVisited.php +++ b/tests/Unit/Fixture/ProfileVisited.php @@ -6,11 +6,14 @@ use Patchlevel\EventSourcing\Aggregate\AggregateChanged; +/** + * @template-extends AggregateChanged + */ final class ProfileVisited extends AggregateChanged { public static function raise(ProfileId $visitedId, ProfileId $visitorId): self { - return self::occur( + return new self( $visitedId->toString(), [ 'visitorId' => $visitorId->toString(), diff --git a/tests/Unit/Pipeline/Middleware/ReplaceEventMiddlewareTest.php b/tests/Unit/Pipeline/Middleware/ReplaceEventMiddlewareTest.php index 36a692f1a..d16a0aef9 100644 --- a/tests/Unit/Pipeline/Middleware/ReplaceEventMiddlewareTest.php +++ b/tests/Unit/Pipeline/Middleware/ReplaceEventMiddlewareTest.php @@ -50,6 +50,7 @@ static function (ProfileCreated $event) { public function testReplaceInvalidClass(): void { + /** @psalm-suppress InvalidArgument */ $middleware = new ReplaceEventMiddleware( MessagePublished::class, static function (ProfileCreated $event) { diff --git a/tests/Unit/Pipeline/Target/ProjectionTargetTest.php b/tests/Unit/Pipeline/Target/ProjectionTargetTest.php index 7ed22e685..89d0f7dba 100644 --- a/tests/Unit/Pipeline/Target/ProjectionTargetTest.php +++ b/tests/Unit/Pipeline/Target/ProjectionTargetTest.php @@ -30,7 +30,6 @@ public function testSave(): void $projectionRepository = new class implements Projection { public static ?AggregateChanged $handledEvent = null; - /** @return iterable, string> */ public function handledEvents(): iterable { yield ProfileCreated::class => 'applyProfileCreated'; diff --git a/tests/Unit/Projection/DefaultProjectionRepositoryTest.php b/tests/Unit/Projection/DefaultProjectionRepositoryTest.php index ea0a2416e..1d44afb88 100644 --- a/tests/Unit/Projection/DefaultProjectionRepositoryTest.php +++ b/tests/Unit/Projection/DefaultProjectionRepositoryTest.php @@ -35,7 +35,6 @@ public function testHandle(): void $projection = new class implements Projection { public static ?AggregateChanged $handledEvent = null; - /** @return iterable, string> */ public function handledEvents(): iterable { yield ProfileCreated::class => 'applyProfileCreated'; @@ -71,7 +70,6 @@ public function testHandleNotSupportedEvent(): void $projection = new class implements Projection { public static ?AggregateChanged $handledEvent = null; - /** @return iterable, string> */ public function handledEvents(): iterable { yield ProfileCreated::class => 'applyProfileCreated'; @@ -105,7 +103,6 @@ public function drop(): void public function testHandleButProjectionsMethodIsMissing(): void { $projection = new class implements Projection { - /** @return iterable, string> */ public function handledEvents(): iterable { yield ProfileCreated::class => 'applyProfileCreated';