Skip to content

Commit

Permalink
Merge pull request #552 from patchlevel/argument-resolver
Browse files Browse the repository at this point in the history
Argument resolver for subscriber
  • Loading branch information
DavidBadura authored Mar 27, 2024
2 parents e3da365 + 89214f4 commit 84c9564
Show file tree
Hide file tree
Showing 26 changed files with 787 additions and 74 deletions.
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 @@ public function metadata(string $subscriber): SubscriberMetadata
$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 @@ public function metadata(string $subscriber): SubscriberMetadata

return $metadata;
}

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

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

if ($type === null) {
throw ArgumentTypeNotSupported::missingType(
$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

0 comments on commit 84c9564

Please sign in to comment.