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

Argument resolver for subscriber #552

Merged
merged 2 commits into from
Mar 27, 2024
Merged
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
34 changes: 11 additions & 23 deletions baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -115,15 +115,14 @@
</PossiblyNullPropertyFetch>
</file>
<file src="src/Subscription/Subscriber/MetadataSubscriberAccessor.php">
<MixedAssignment>
<code><![CDATA[$arguments[]]]></code>
</MixedAssignment>
<MixedMethodCall>
<code><![CDATA[$method]]></code>
<code><![CDATA[$method]]></code>
<code><![CDATA[$method]]></code>
<code><![CDATA[$methodName]]></code>
</MixedMethodCall>
<MixedReturnTypeCoercion>
<code><![CDATA[$this->subscriber->$method(...)]]></code>
<code><![CDATA[Closure(Message):void]]></code>
</MixedReturnTypeCoercion>
</file>
<file src="tests/Benchmark/BasicImplementation/Profile.php">
<PropertyNotSetInConstructor>
Expand All @@ -134,15 +133,13 @@
</file>
<file src="tests/Benchmark/PersonalDataBench.php">
<MissingConstructor>
<code><![CDATA[$bus]]></code>
<code><![CDATA[$id]]></code>
<code><![CDATA[$repository]]></code>
<code><![CDATA[$store]]></code>
</MissingConstructor>
</file>
<file src="tests/Benchmark/SimpleSetupBench.php">
<MissingConstructor>
<code><![CDATA[$bus]]></code>
<code><![CDATA[$id]]></code>
<code><![CDATA[$repository]]></code>
<code><![CDATA[$store]]></code>
Expand All @@ -151,7 +148,6 @@
<file src="tests/Benchmark/SnapshotsBench.php">
<MissingConstructor>
<code><![CDATA[$adapter]]></code>
<code><![CDATA[$bus]]></code>
<code><![CDATA[$id]]></code>
<code><![CDATA[$repository]]></code>
<code><![CDATA[$snapshotStore]]></code>
Expand All @@ -163,15 +159,13 @@
<code><![CDATA[$this->id]]></code>
</ArgumentTypeCoercion>
<MissingConstructor>
<code><![CDATA[$bus]]></code>
<code><![CDATA[$id]]></code>
<code><![CDATA[$repository]]></code>
<code><![CDATA[$store]]></code>
</MissingConstructor>
</file>
<file src="tests/Benchmark/SubscriptionEngineBench.php">
<MissingConstructor>
<code><![CDATA[$bus]]></code>
<code><![CDATA[$id]]></code>
<code><![CDATA[$repository]]></code>
<code><![CDATA[$store]]></code>
Expand Down Expand Up @@ -202,13 +196,6 @@
<code><![CDATA[$name]]></code>
</PropertyNotSetInConstructor>
</file>
<file src="tests/Integration/Pipeline/Aggregate/Profile.php">
<PropertyNotSetInConstructor>
<code><![CDATA[$id]]></code>
<code><![CDATA[$privacy]]></code>
<code><![CDATA[$visited]]></code>
</PropertyNotSetInConstructor>
</file>
<file src="tests/Integration/Store/Profile.php">
<PropertyNotSetInConstructor>
<code><![CDATA[$id]]></code>
Expand Down Expand Up @@ -291,12 +278,13 @@
<code><![CDATA[$id]]></code>
</PropertyNotSetInConstructor>
</file>
<file src="tests/Unit/Pipeline/Source/InMemorySourceTest.php">
<InvalidMethodCall>
<code><![CDATA[current]]></code>
<code><![CDATA[current]]></code>
<code><![CDATA[next]]></code>
</InvalidMethodCall>
<file src="tests/Unit/Metadata/Subscriber/AttributeSubscriberMetadataFactoryTest.php">
<MissingParamType>
<code><![CDATA[$message]]></code>
</MissingParamType>
<ReservedWord>
<code><![CDATA[ProfileVisited&ProfileCreated $event]]></code>
</ReservedWord>
</file>
<file src="tests/Unit/Subscription/Engine/DefaultSubscriptionEngineTest.php">
<PossiblyUndefinedArrayOffset>
Expand Down
1 change: 1 addition & 0 deletions deptrac.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ deptrac:
- Metadata
- Subscription
Subscription:
- Aggregate
- Attribute
- Clock
- Message
Expand Down
14 changes: 14 additions & 0 deletions src/Metadata/Subscriber/ArgumentMetadata.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

declare(strict_types=1);

namespace Patchlevel\EventSourcing\Metadata\Subscriber;

final class ArgumentMetadata
{
public function __construct(
public readonly string $name,
public readonly string $type,
) {
}
}
36 changes: 36 additions & 0 deletions src/Metadata/Subscriber/ArgumentTypeNotSupported.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

namespace Patchlevel\EventSourcing\Metadata\Subscriber;

use Patchlevel\EventSourcing\Metadata\MetadataException;

use function sprintf;

final class ArgumentTypeNotSupported extends MetadataException
{
public static function missingType(string $class, string $method, string $argumentName): self
{
return new self(
sprintf(
'Argument type for method "%s" in class "%s" is not supported. Argument "%s" must have a type.',
$method,
$class,
$argumentName,
),
);
}

public static function onlyNamedTypeSupported(string $class, string $method, string $argumentName): self
{
return new self(
sprintf(
'Argument type for method "%s" in class "%s" is not supported. Argument "%s" must not have a union or intersection type.',
$method,
$class,
$argumentName,
),
);
}
}
39 changes: 38 additions & 1 deletion src/Metadata/Subscriber/AttributeSubscriberMetadataFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
use Patchlevel\EventSourcing\Attribute\Teardown;
use ReflectionAttribute;
use ReflectionClass;
use ReflectionMethod;
use ReflectionNamedType;

use function array_key_exists;

Expand Down Expand Up @@ -48,7 +50,7 @@
$instance = $attribute->newInstance();
$eventClass = $instance->eventClass;

$subscribeMethods[$eventClass][] = $method->getName();
$subscribeMethods[$eventClass][] = $this->subscribeMethod($method);
}

if ($method->getAttributes(Setup::class)) {
Expand Down Expand Up @@ -91,4 +93,39 @@

return $metadata;
}

private function subscribeMethod(ReflectionMethod $method): SubscribeMethodMetadata
{
$arguments = [];

foreach ($method->getParameters() as $parameter) {
$type = $parameter->getType();

if ($type === null) {
throw ArgumentTypeNotSupported::missingType(

Check warning on line 105 in src/Metadata/Subscriber/AttributeSubscriberMetadataFactory.php

View workflow job for this annotation

GitHub Actions / Mutation tests on diff (locked, 8.3, ubuntu-latest)

Escaped Mutant for Mutator "Throw_": --- Original +++ New @@ @@ foreach ($method->getParameters() as $parameter) { $type = $parameter->getType(); if ($type === null) { - throw ArgumentTypeNotSupported::missingType($method->getDeclaringClass()->getName(), $method->getName(), $parameter->getName()); + ArgumentTypeNotSupported::missingType($method->getDeclaringClass()->getName(), $method->getName(), $parameter->getName()); } if (!$type instanceof ReflectionNamedType) { throw ArgumentTypeNotSupported::onlyNamedTypeSupported($method->getDeclaringClass()->getName(), $method->getName(), $parameter->getName());
$method->getDeclaringClass()->getName(),
$method->getName(),
$parameter->getName(),
);
}

if (!$type instanceof ReflectionNamedType) {
throw ArgumentTypeNotSupported::onlyNamedTypeSupported(
$method->getDeclaringClass()->getName(),
$method->getName(),
$parameter->getName(),
);
}

$arguments[] = new ArgumentMetadata(
$parameter->getName(),
$type->getName(),
);
}

return new SubscribeMethodMetadata(
$method->getName(),
$arguments,
);
}
}
15 changes: 15 additions & 0 deletions src/Metadata/Subscriber/SubscribeMethodMetadata.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Patchlevel\EventSourcing\Metadata\Subscriber;

final class SubscribeMethodMetadata
{
/** @param list<ArgumentMetadata> $arguments */
public function __construct(
public readonly string $name,
public readonly array $arguments = [],
) {
}
}
2 changes: 1 addition & 1 deletion src/Metadata/Subscriber/SubscriberMetadata.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public function __construct(
public readonly string $id,
public readonly string $group = Subscription::DEFAULT_GROUP,
public readonly RunMode $runMode = RunMode::FromBeginning,
/** @var array<class-string|"*", list<string>> */
/** @var array<class-string|"*", list<SubscribeMethodMetadata>> */
public readonly array $subscribeMethods = [],
public readonly string|null $setupMethod = null,
public readonly string|null $teardownMethod = null,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace Patchlevel\EventSourcing\Subscription\Subscriber\ArgumentResolver;

use Patchlevel\EventSourcing\Aggregate\AggregateHeader;
use Patchlevel\EventSourcing\Message\Message;
use Patchlevel\EventSourcing\Metadata\Subscriber\ArgumentMetadata;

use function in_array;

final class AggregateIdArgumentResolver implements ArgumentResolver
{
public function resolve(ArgumentMetadata $argument, Message $message): string
{
return $message->header(AggregateHeader::class)->aggregateId;
}

public function support(ArgumentMetadata $argument, string $eventClass): bool
{
return $argument->type === 'string' && in_array($argument->name, ['aggregateId', 'aggregateRootId']);
}
}
15 changes: 15 additions & 0 deletions src/Subscription/Subscriber/ArgumentResolver/ArgumentResolver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Patchlevel\EventSourcing\Subscription\Subscriber\ArgumentResolver;

use Patchlevel\EventSourcing\Message\Message;
use Patchlevel\EventSourcing\Metadata\Subscriber\ArgumentMetadata;

interface ArgumentResolver
{
public function resolve(ArgumentMetadata $argument, Message $message): mixed;

public function support(ArgumentMetadata $argument, string $eventClass): bool;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace Patchlevel\EventSourcing\Subscription\Subscriber\ArgumentResolver;

use Patchlevel\EventSourcing\Message\Message;
use Patchlevel\EventSourcing\Metadata\Subscriber\ArgumentMetadata;

use function class_exists;
use function is_a;

final class EventArgumentResolver implements ArgumentResolver
{
public function resolve(ArgumentMetadata $argument, Message $message): object
{
return $message->event();
}

public function support(ArgumentMetadata $argument, string $eventClass): bool
{
return class_exists($argument->type) && is_a($eventClass, $argument->type, true);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace Patchlevel\EventSourcing\Subscription\Subscriber\ArgumentResolver;

use Patchlevel\EventSourcing\Message\Message;
use Patchlevel\EventSourcing\Metadata\Subscriber\ArgumentMetadata;

final class MessageArgumentResolver implements ArgumentResolver
{
public function resolve(ArgumentMetadata $argument, Message $message): Message
{
return $message;
}

public function support(ArgumentMetadata $argument, string $eventClass): bool
{
return $argument->type === Message::class;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace Patchlevel\EventSourcing\Subscription\Subscriber\ArgumentResolver;

use DateTimeImmutable;
use Patchlevel\EventSourcing\Aggregate\AggregateHeader;
use Patchlevel\EventSourcing\Message\Message;
use Patchlevel\EventSourcing\Metadata\Subscriber\ArgumentMetadata;

final class RecordedOnArgumentResolver implements ArgumentResolver
{
public function resolve(ArgumentMetadata $argument, Message $message): DateTimeImmutable
{
return $message->header(AggregateHeader::class)->recordedOn;
}

public function support(ArgumentMetadata $argument, string $eventClass): bool
{
return $argument->type === DateTimeImmutable::class;
}
}
Loading
Loading