Skip to content

Commit

Permalink
Merge pull request #297 from patchlevel/projector
Browse files Browse the repository at this point in the history
add projector and projectionist
  • Loading branch information
DavidBadura authored Oct 10, 2022
2 parents 0d04bb1 + 0febbd0 commit a0401dd
Show file tree
Hide file tree
Showing 58 changed files with 3,242 additions and 50 deletions.
271 changes: 271 additions & 0 deletions baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,30 @@
<code>$sleep</code>
</ArgumentTypeCoercion>
</file>
<file src="src/Console/Command/ProjectionCommand.php">
<DeprecatedClass occurrences="10">
<code>MetadataAwareProjectionHandler</code>
<code>MetadataAwareProjectionHandler::class</code>
<code>Projection</code>
<code>ProjectionHandler</code>
<code>ProjectionHandler</code>
<code>ProjectionHandler</code>
<code>ProjectionHandler</code>
<code>non-empty-array&lt;class-string&lt;Projection&gt;&gt;</code>
<code>non-empty-array&lt;class-string&lt;Projection&gt;&gt;|null</code>
</DeprecatedClass>
</file>
<file src="src/Console/Command/ProjectionRebuildCommand.php">
<DeprecatedClass occurrences="1">
<code>ProjectionHandler</code>
</DeprecatedClass>
</file>
<file src="src/Console/Command/ProjectionistRunCommand.php">
<ArgumentTypeCoercion occurrences="2">
<code>$messageLimit</code>
<code>$sleep</code>
</ArgumentTypeCoercion>
</file>
<file src="src/Console/Command/SchemaCreateCommand.php">
<DeprecatedClass occurrences="2">
<code>SchemaManager|SchemaDirector</code>
Expand Down Expand Up @@ -43,6 +67,81 @@
<code>array&lt;class-string, string&gt;</code>
</MoreSpecificReturnType>
</file>
<file src="src/Metadata/Projection/AttributeProjectionMetadataFactory.php">
<DeprecatedClass occurrences="3">
<code>array</code>
<code>class-string&lt;Projection&gt;</code>
<code>private array $projectionMetadata = [];</code>
</DeprecatedClass>
</file>
<file src="src/Metadata/Projection/DuplicateCreateMethod.php">
<DeprecatedClass occurrences="1">
<code>class-string&lt;Projection&gt;</code>
</DeprecatedClass>
</file>
<file src="src/Metadata/Projection/DuplicateDropMethod.php">
<DeprecatedClass occurrences="1">
<code>class-string&lt;Projection&gt;</code>
</DeprecatedClass>
</file>
<file src="src/Metadata/Projection/DuplicateHandleMethod.php">
<DeprecatedClass occurrences="1">
<code>class-string&lt;Projection&gt;</code>
</DeprecatedClass>
</file>
<file src="src/Metadata/Projection/ProjectionMetadataFactory.php">
<DeprecatedClass occurrences="1">
<code>class-string&lt;Projection&gt;</code>
</DeprecatedClass>
</file>
<file src="src/Pipeline/Source/StoreSource.php">
<DeprecatedClass occurrences="2">
<code>PipelineStore</code>
<code>PipelineStore</code>
</DeprecatedClass>
</file>
<file src="src/Pipeline/Target/ProjectionHandlerTarget.php">
<DeprecatedClass occurrences="2">
<code>ProjectionHandler</code>
<code>ProjectionHandler</code>
</DeprecatedClass>
</file>
<file src="src/Pipeline/Target/ProjectionTarget.php">
<DeprecatedClass occurrences="3">
<code>MetadataAwareProjectionHandler</code>
<code>Projection</code>
</DeprecatedClass>
</file>
<file src="src/Projection/MetadataAwareProjectionHandler.php">
<DeprecatedClass occurrences="3">
<code>iterable</code>
<code>iterable&lt;Projection&gt;</code>
<code>iterable&lt;Projection&gt;</code>
</DeprecatedClass>
<DeprecatedInterface occurrences="1">
<code>MetadataAwareProjectionHandler</code>
</DeprecatedInterface>
</file>
<file src="src/Projection/MetadataProjectorResolver.php">
<DeprecatedClass occurrences="3">
<code>Projection</code>
<code>Projection</code>
<code>Projection</code>
</DeprecatedClass>
</file>
<file src="src/Projection/ProjectionListener.php">
<DeprecatedClass occurrences="2">
<code>ProjectionHandler</code>
<code>ProjectionHandler</code>
</DeprecatedClass>
</file>
<file src="src/Projection/ProjectorResolver.php">
<DeprecatedClass occurrences="3">
<code>Projection</code>
<code>Projection</code>
<code>Projection</code>
</DeprecatedClass>
</file>
<file src="src/Repository/DefaultRepository.php">
<ArgumentTypeCoercion occurrences="1">
<code>$messages[0]-&gt;playhead() - 1</code>
Expand Down Expand Up @@ -92,10 +191,23 @@
</MixedReturnTypeCoercion>
</file>
<file src="src/Store/MultiTableStore.php">
<DeprecatedInterface occurrences="1">
<code>MultiTableStore</code>
</DeprecatedInterface>
<UnnecessaryVarAnnotation occurrences="1">
<code>array{id: string, aggregate_id: string, playhead: string, event: string, payload: string, recorded_on: string, custom_headers: string}|null</code>
</UnnecessaryVarAnnotation>
</file>
<file src="src/Store/SingleTableStore.php">
<DeprecatedInterface occurrences="1">
<code>SingleTableStore</code>
</DeprecatedInterface>
</file>
<file src="tests/Benchmark/BasicImplementation/Projection/ProfileProjector.php">
<DeprecatedInterface occurrences="1">
<code>ProfileProjector</code>
</DeprecatedInterface>
</file>
<file src="tests/Benchmark/LoadEventsBench.php">
<MissingConstructor occurrences="3">
<code>$bus</code>
Expand All @@ -112,13 +224,84 @@
</MissingConstructor>
</file>
<file src="tests/Benchmark/WriteEventsBench.php">
<DeprecatedClass occurrences="2">
<code>new ProjectionListener($projectionRepository)</code>
</DeprecatedClass>
<MissingConstructor occurrences="4">
<code>$bus</code>
<code>$profile</code>
<code>$repository</code>
<code>$store</code>
</MissingConstructor>
</file>
<file src="tests/Integration/BankAccountSplitStream/IntegrationTest.php">
<DeprecatedClass occurrences="4">
<code>new MetadataAwareProjectionHandler([$bankAccountProjection])</code>
<code>new MetadataAwareProjectionHandler([$bankAccountProjection])</code>
<code>new ProjectionListener($projectionRepository)</code>
<code>new ProjectionListener($projectionRepository)</code>
</DeprecatedClass>
</file>
<file src="tests/Integration/BankAccountSplitStream/Projection/BankAccountProjection.php">
<DeprecatedInterface occurrences="1">
<code>BankAccountProjection</code>
</DeprecatedInterface>
</file>
<file src="tests/Integration/BasicImplementation/Projection/ProfileProjection.php">
<DeprecatedInterface occurrences="1">
<code>ProfileProjection</code>
</DeprecatedInterface>
</file>
<file src="tests/Integration/Outbox/OutboxTest.php">
<DeprecatedClass occurrences="2">
<code>new ProjectionListener($projectionRepository)</code>
</DeprecatedClass>
</file>
<file src="tests/Integration/Outbox/Projection/ProfileProjection.php">
<DeprecatedInterface occurrences="1">
<code>ProfileProjection</code>
</DeprecatedInterface>
</file>
<file src="tests/Integration/Projectionist/Projection/ProfileProjection.php">
<DeprecatedInterface occurrences="1">
<code>ProfileProjection</code>
</DeprecatedInterface>
</file>
<file src="tests/Unit/Console/Command/ProjectionCreateCommandTest.php">
<DeprecatedClass occurrences="2">
<code>$this-&gt;prophesize(ProjectionHandler::class)</code>
<code>new MetadataAwareProjectionHandler([$projectionA, $projectionB])</code>
</DeprecatedClass>
</file>
<file src="tests/Unit/Console/Command/ProjectionDropCommandTest.php">
<DeprecatedClass occurrences="2">
<code>$this-&gt;prophesize(ProjectionHandler::class)</code>
<code>new MetadataAwareProjectionHandler([$projectionA, $projectionB])</code>
</DeprecatedClass>
</file>
<file src="tests/Unit/Console/Command/ProjectionRebuildCommandTest.php">
<DeprecatedClass occurrences="9">
<code>$this-&gt;prophesize(PipelineStore::class)</code>
<code>$this-&gt;prophesize(PipelineStore::class)</code>
<code>$this-&gt;prophesize(PipelineStore::class)</code>
<code>$this-&gt;prophesize(PipelineStore::class)</code>
<code>$this-&gt;prophesize(ProjectionHandler::class)</code>
<code>$this-&gt;prophesize(ProjectionHandler::class)</code>
<code>$this-&gt;prophesize(ProjectionHandler::class)</code>
<code>new MetadataAwareProjectionHandler([$projectionA, $projectionB])</code>
<code>new MetadataAwareProjectionHandler([$projectionA, $projectionB])</code>
</DeprecatedClass>
</file>
<file src="tests/Unit/Fixture/Dummy2Projection.php">
<DeprecatedInterface occurrences="1">
<code>Dummy2Projection</code>
</DeprecatedInterface>
</file>
<file src="tests/Unit/Fixture/DummyProjection.php">
<DeprecatedInterface occurrences="1">
<code>DummyProjection</code>
</DeprecatedInterface>
</file>
<file src="tests/Unit/Fixture/MessageNormalizer.php">
<MixedArgumentTypeCoercion occurrences="1">
<code>$value</code>
Expand All @@ -129,6 +312,94 @@
<code>$event</code>
</MissingParamType>
</file>
<file src="tests/Unit/Metadata/Projection/AttributeProjectionMetadataFactoryTest.php">
<DeprecatedInterface occurrences="5">
<code>class implements Projection {</code>
<code>class implements Projection {</code>
<code>class implements Projection {</code>
<code>class implements Projection {</code>
<code>class implements Projection {</code>
</DeprecatedInterface>
</file>
<file src="tests/Unit/Pipeline/Source/StoreSourceTest.php">
<DeprecatedClass occurrences="4">
<code>$this-&gt;prophesize(PipelineStore::class)</code>
<code>$this-&gt;prophesize(PipelineStore::class)</code>
<code>$this-&gt;prophesize(PipelineStore::class)</code>
<code>$this-&gt;prophesize(PipelineStore::class)</code>
</DeprecatedClass>
</file>
<file src="tests/Unit/Pipeline/Target/ProjectionHandlerTargetTest.php">
<DeprecatedClass occurrences="1">
<code>$this-&gt;prophesize(ProjectionHandler::class)</code>
</DeprecatedClass>
</file>
<file src="tests/Unit/Pipeline/Target/ProjectionTargetTest.php">
<DeprecatedInterface occurrences="1">
<code>class implements Projection {</code>
</DeprecatedInterface>
</file>
<file src="tests/Unit/Pipeline/Target/StoreTargetTest.php">
<DeprecatedClass occurrences="1">
<code>$this-&gt;prophesize(PipelineStore::class)</code>
</DeprecatedClass>
</file>
<file src="tests/Unit/Projection/DefaultProjectionistTest.php">
<DeprecatedInterface occurrences="9">
<code>class implements Projector {</code>
<code>class implements Projector {</code>
<code>class implements Projector {</code>
<code>class implements Projector {</code>
<code>class implements Projector {</code>
<code>class implements Projector {</code>
<code>class implements Projector {</code>
<code>class implements Projector {</code>
<code>class implements Projector {</code>
</DeprecatedInterface>
</file>
<file src="tests/Unit/Projection/DefaultProjectorRepositoryTest.php">
<DeprecatedInterface occurrences="2">
<code>class implements Projector {</code>
<code>class implements Projector {</code>
</DeprecatedInterface>
</file>
<file src="tests/Unit/Projection/MetadataAwareProjectionHandlerTest.php">
<DeprecatedClass occurrences="5">
<code>new MetadataAwareProjectionHandler([$projection])</code>
<code>new MetadataAwareProjectionHandler([$projection])</code>
<code>new MetadataAwareProjectionHandler([$projection])</code>
<code>new MetadataAwareProjectionHandler([$projection])</code>
<code>new MetadataAwareProjectionHandler([])</code>
</DeprecatedClass>
<DeprecatedInterface occurrences="4">
<code>class implements Projection {</code>
<code>class implements Projection {</code>
<code>class implements Projection {</code>
<code>class implements Projection {</code>
</DeprecatedInterface>
</file>
<file src="tests/Unit/Projection/MetadataProjectorResolverTest.php">
<DeprecatedInterface occurrences="6">
<code>class implements Projection {</code>
<code>class implements Projection {</code>
<code>class implements Projection {</code>
<code>class implements Projection {</code>
<code>class implements Projection {</code>
<code>class implements Projection {</code>
</DeprecatedInterface>
</file>
<file src="tests/Unit/Projection/ProjectionListenerTest.php">
<DeprecatedClass occurrences="2">
<code>$this-&gt;prophesize(ProjectionHandler::class)</code>
<code>new ProjectionListener($projectionRepository-&gt;reveal())</code>
</DeprecatedClass>
</file>
<file src="tests/Unit/Projection/SyncProjectorListenerTest.php">
<DeprecatedInterface occurrences="2">
<code>class implements Projector {</code>
<code>class implements Projector {</code>
</DeprecatedInterface>
</file>
<file src="tests/Unit/Schema/DoctrineSchemaDirectorTest.php">
<InternalMethod occurrences="2">
<code>new Comparator()</code>
Expand Down
28 changes: 19 additions & 9 deletions docs/pages/projection.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ and everything can always be reproduced from the events.
The target of a projection can be anything.
Either a file, a relational database, a no-sql database like mongodb or an elasticsearch.

## Define Projection
## Define Projector

To create a projection you need a projector.
In this example we always create a new data set in a relational database when a profile is created:

```php
Expand All @@ -18,16 +19,25 @@ use Patchlevel\EventSourcing\Attribute\Create;
use Patchlevel\EventSourcing\Attribute\Drop;
use Patchlevel\EventSourcing\Attribute\Handle;
use Patchlevel\EventSourcing\EventBus\Message;
use Patchlevel\EventSourcing\Projection\Projection;
use Patchlevel\EventSourcing\Projection\Projector;
use Patchlevel\EventSourcing\Projection\ProjectorId;

final class ProfileProjection implements Projection
final class ProfileProjection implements Projector
{
private Connection $connection;

public function __construct(Connection $connection)
{
$this->connection = $connection;
}

public function projectorId(): ProjectorId
{
return new ProjectorId(
name: 'profile',
version: 1
);
}

#[Create]
public function create(): void
Expand Down Expand Up @@ -59,26 +69,26 @@ final class ProfileProjection implements Projection

!!! danger

You should not execute any actions with projections,
You should not execute any actions with projectors,
otherwise these will be executed again if you rebuild the projection!

!!! tip

If you are using psalm then you can install the event sourcing [plugin](https://github.com/patchlevel/event-sourcing-psalm-plugin)
to make the event method return the correct type.

Projections have a `create` and a `drop` method that is executed when the projection is created or deleted.
Projectors have a `create` and a `drop` method that is executed when the projection is created or deleted.
In some cases it may be that no schema has to be created for the projection, as the target does it automatically.

In order for the projection to know which method is responsible for which event,
In order for the projector to know which method is responsible for which event,
the methods must be given the `Handle` attribute with the respective event class name.

As soon as the event has been dispatched, the appropriate methods are then executed.
Several projections can also listen to the same event.
Several projectors can also listen to the same event.

## Register projections
## Register projector

So that the projections are known and also executed, you have to add them to the `ProjectionHandler`.
So that the projectors are known and also executed, you have to add them to the `ProjectionHandler`.
Then add this to the event bus using the `ProjectionListener`.

```php
Expand Down
Loading

0 comments on commit a0401dd

Please sign in to comment.