diff --git a/baseline.xml b/baseline.xml
index 22ff0c1fe..1009d302a 100644
--- a/baseline.xml
+++ b/baseline.xml
@@ -121,7 +121,7 @@
-
+
diff --git a/src/Subscription/Subscriber/NoSuitableResolver.php b/src/Subscription/Subscriber/NoSuitableResolver.php
index a7a096410..f106931a3 100644
--- a/src/Subscription/Subscriber/NoSuitableResolver.php
+++ b/src/Subscription/Subscriber/NoSuitableResolver.php
@@ -8,7 +8,7 @@
use function sprintf;
-class NoSuitableResolver extends RuntimeException
+final class NoSuitableResolver extends RuntimeException
{
public function __construct(string $class, string $methodName, string $argumentName)
{
diff --git a/tests/Unit/Metadata/Subscriber/AttributeSubscriberMetadataFactoryTest.php b/tests/Unit/Metadata/Subscriber/AttributeSubscriberMetadataFactoryTest.php
index d8a917ec7..999e397e5 100644
--- a/tests/Unit/Metadata/Subscriber/AttributeSubscriberMetadataFactoryTest.php
+++ b/tests/Unit/Metadata/Subscriber/AttributeSubscriberMetadataFactoryTest.php
@@ -10,6 +10,8 @@
use Patchlevel\EventSourcing\Attribute\Subscribe;
use Patchlevel\EventSourcing\Attribute\Subscriber;
use Patchlevel\EventSourcing\Attribute\Teardown;
+use Patchlevel\EventSourcing\Message\Message;
+use Patchlevel\EventSourcing\Metadata\Subscriber\ArgumentMetadata;
use Patchlevel\EventSourcing\Metadata\Subscriber\AttributeSubscriberMetadataFactory;
use Patchlevel\EventSourcing\Metadata\Subscriber\ClassIsNotASubscriber;
use Patchlevel\EventSourcing\Metadata\Subscriber\DuplicateSetupMethod;
@@ -163,6 +165,42 @@ public function handle(): void
);
}
+ public function testSubscribeAttributes(): void
+ {
+ $subscriber = new #[Subscriber('foo', RunMode::FromBeginning)]
+ class {
+ #[Subscribe(ProfileVisited::class)]
+ public function profileVisited(Message $message): void
+ {
+ }
+
+ #[Subscribe(ProfileCreated::class)]
+ public function profileCreated(ProfileCreated $profileCreated, string $aggregateId): void
+ {
+ }
+ };
+
+ $metadataFactory = new AttributeSubscriberMetadataFactory();
+ $metadata = $metadataFactory->metadata($subscriber::class);
+
+ self::assertEquals(
+ [
+ ProfileVisited::class => [
+ new SubscribeMethodMetadata('profileVisited', [
+ new ArgumentMetadata('message', Message::class),
+ ]),
+ ],
+ ProfileCreated::class => [
+ new SubscribeMethodMetadata('profileCreated', [
+ new ArgumentMetadata('profileCreated', ProfileCreated::class),
+ new ArgumentMetadata('aggregateId', 'string'),
+ ]),
+ ],
+ ],
+ $metadata->subscribeMethods,
+ );
+ }
+
public function testDuplicateSetupAttributeException(): void
{
$this->expectException(DuplicateSetupMethod::class);
diff --git a/tests/Unit/Subscription/Subscriber/ArgumentResolver/AggregateIdArgumentResolverTest.php b/tests/Unit/Subscription/Subscriber/ArgumentResolver/AggregateIdArgumentResolverTest.php
new file mode 100644
index 000000000..00db10f22
--- /dev/null
+++ b/tests/Unit/Subscription/Subscriber/ArgumentResolver/AggregateIdArgumentResolverTest.php
@@ -0,0 +1,63 @@
+support(
+ new ArgumentMetadata('aggregateId', 'string'),
+ ProfileCreated::class,
+ ),
+ );
+
+ self::assertTrue(
+ $resolver->support(
+ new ArgumentMetadata('aggregateRootId', 'string'),
+ ProfileCreated::class,
+ ),
+ );
+
+ self::assertFalse(
+ $resolver->support(
+ new ArgumentMetadata('foo', 'string'),
+ ProfileCreated::class,
+ ),
+ );
+ }
+
+ public function testResolve(): void
+ {
+ $event = new ProfileVisited(ProfileId::fromString('1'));
+
+ $resolver = new AggregateIdArgumentResolver();
+ $message = (new Message($event))->withHeader(
+ new AggregateHeader('foo', 'bar', 1, new DateTimeImmutable()),
+ );
+
+ self::assertSame(
+ 'bar',
+ $resolver->resolve(
+ new ArgumentMetadata('foo', 'string'),
+ $message,
+ ),
+ );
+ }
+}
diff --git a/tests/Unit/Subscription/Subscriber/ArgumentResolver/EventArgumentResolverTest.php b/tests/Unit/Subscription/Subscriber/ArgumentResolver/EventArgumentResolverTest.php
new file mode 100644
index 000000000..14bb807c4
--- /dev/null
+++ b/tests/Unit/Subscription/Subscriber/ArgumentResolver/EventArgumentResolverTest.php
@@ -0,0 +1,52 @@
+support(
+ new ArgumentMetadata('foo', ProfileCreated::class),
+ ProfileCreated::class,
+ ),
+ );
+
+ self::assertFalse(
+ $resolver->support(
+ new ArgumentMetadata('foo', ProfileVisited::class),
+ ProfileCreated::class,
+ ),
+ );
+ }
+
+ public function testResolve(): void
+ {
+ $event = new ProfileVisited(ProfileId::fromString('1'));
+
+ $resolver = new EventArgumentResolver();
+ $message = new Message($event);
+
+ self::assertSame(
+ $event,
+ $resolver->resolve(
+ new ArgumentMetadata('foo', ProfileVisited::class),
+ $message,
+ ),
+ );
+ }
+}
diff --git a/tests/Unit/Subscription/Subscriber/ArgumentResolver/MessageArgumentResolverTest.php b/tests/Unit/Subscription/Subscriber/ArgumentResolver/MessageArgumentResolverTest.php
new file mode 100644
index 000000000..6dc808a5c
--- /dev/null
+++ b/tests/Unit/Subscription/Subscriber/ArgumentResolver/MessageArgumentResolverTest.php
@@ -0,0 +1,48 @@
+support(
+ new ArgumentMetadata('foo', Message::class),
+ 'qux',
+ ),
+ );
+
+ self::assertFalse(
+ $resolver->support(
+ new ArgumentMetadata('foo', 'bar'),
+ 'qux',
+ ),
+ );
+ }
+
+ public function testResolve(): void
+ {
+ $resolver = new MessageArgumentResolver();
+ $message = new Message(new stdClass());
+
+ self::assertSame(
+ $message,
+ $resolver->resolve(
+ new ArgumentMetadata('foo', Message::class),
+ $message,
+ ),
+ );
+ }
+}
diff --git a/tests/Unit/Subscription/Subscriber/ArgumentResolver/RecordedOnArgumentResolverTest.php b/tests/Unit/Subscription/Subscriber/ArgumentResolver/RecordedOnArgumentResolverTest.php
new file mode 100644
index 000000000..6a4480166
--- /dev/null
+++ b/tests/Unit/Subscription/Subscriber/ArgumentResolver/RecordedOnArgumentResolverTest.php
@@ -0,0 +1,59 @@
+support(
+ new ArgumentMetadata('foo', DateTimeImmutable::class),
+ 'qux',
+ ),
+ );
+
+ self::assertFalse(
+ $resolver->support(
+ new ArgumentMetadata('foo', 'bar'),
+ 'qux',
+ ),
+ );
+ }
+
+ public function testResolve(): void
+ {
+ $date = new DateTimeImmutable();
+
+ $resolver = new RecordedOnArgumentResolver();
+ $message = (new Message(new stdClass()))->withHeader(
+ new AggregateHeader(
+ 'foo',
+ 'bar',
+ 1,
+ $date,
+ ),
+ );
+
+ self::assertSame(
+ $date,
+ $resolver->resolve(
+ new ArgumentMetadata('foo', DateTimeImmutable::class),
+ $message,
+ ),
+ );
+ }
+}
diff --git a/tests/Unit/Subscription/Subscriber/MetadataSubscriberAccessorRepositoryTest.php b/tests/Unit/Subscription/Subscriber/MetadataSubscriberAccessorRepositoryTest.php
index 96d02c610..2970e4088 100644
--- a/tests/Unit/Subscription/Subscriber/MetadataSubscriberAccessorRepositoryTest.php
+++ b/tests/Unit/Subscription/Subscriber/MetadataSubscriberAccessorRepositoryTest.php
@@ -5,6 +5,8 @@
namespace Patchlevel\EventSourcing\Tests\Unit\Subscription\Subscriber;
use Patchlevel\EventSourcing\Attribute\Subscriber;
+use Patchlevel\EventSourcing\Message\Message;
+use Patchlevel\EventSourcing\Metadata\Subscriber\ArgumentMetadata;
use Patchlevel\EventSourcing\Metadata\Subscriber\AttributeSubscriberMetadataFactory;
use Patchlevel\EventSourcing\Subscription\RunMode;
use Patchlevel\EventSourcing\Subscription\Subscriber\ArgumentResolver;
@@ -32,15 +34,29 @@ class {
};
$metadataFactory = new AttributeSubscriberMetadataFactory();
+ $customResolver = new class implements ArgumentResolver\ArgumentResolver {
+ public function resolve(ArgumentMetadata $argument, Message $message): mixed
+ {
+ return null;
+ }
+
+ public function support(ArgumentMetadata $argument, string $eventClass): bool
+ {
+ return false;
+ }
+ };
+
$repository = new MetadataSubscriberAccessorRepository(
[$subscriber],
$metadataFactory,
+ [$customResolver],
);
$accessor = new MetadataSubscriberAccessor(
$subscriber,
$metadataFactory->metadata($subscriber::class),
[
+ $customResolver,
new ArgumentResolver\MessageArgumentResolver(),
new ArgumentResolver\EventArgumentResolver(),
new ArgumentResolver\AggregateIdArgumentResolver(),
diff --git a/tests/Unit/Subscription/Subscriber/MetadataSubscriberAccessorTest.php b/tests/Unit/Subscription/Subscriber/MetadataSubscriberAccessorTest.php
index dff93706e..1991d6c5b 100644
--- a/tests/Unit/Subscription/Subscriber/MetadataSubscriberAccessorTest.php
+++ b/tests/Unit/Subscription/Subscriber/MetadataSubscriberAccessorTest.php
@@ -11,9 +11,13 @@
use Patchlevel\EventSourcing\Message\Message;
use Patchlevel\EventSourcing\Metadata\Subscriber\AttributeSubscriberMetadataFactory;
use Patchlevel\EventSourcing\Subscription\RunMode;
+use Patchlevel\EventSourcing\Subscription\Subscriber\ArgumentResolver\EventArgumentResolver;
use Patchlevel\EventSourcing\Subscription\Subscriber\ArgumentResolver\MessageArgumentResolver;
use Patchlevel\EventSourcing\Subscription\Subscriber\MetadataSubscriberAccessor;
+use Patchlevel\EventSourcing\Subscription\Subscriber\NoSuitableResolver;
use Patchlevel\EventSourcing\Tests\Unit\Fixture\ProfileCreated;
+use Patchlevel\EventSourcing\Tests\Unit\Fixture\ProfileId;
+use Patchlevel\EventSourcing\Tests\Unit\Fixture\ProfileVisited;
use PHPUnit\Framework\TestCase;
/** @covers \Patchlevel\EventSourcing\Subscription\Subscriber\MetadataSubscriberAccessor */
@@ -68,9 +72,12 @@ public function testSubscribeMethod(): void
{
$subscriber = new #[Subscriber('profile', RunMode::FromBeginning)]
class {
- #[Subscribe(ProfileCreated::class)]
- public function onProfileCreated(Message $message): void
+ public Message|null $message = null;
+
+ #[Subscribe(ProfileVisited::class)]
+ public function onProfileVisited(Message $message): void
{
+ $this->message = $message;
}
};
@@ -82,11 +89,15 @@ public function onProfileCreated(Message $message): void
],
);
- $result = $accessor->subscribeMethods(ProfileCreated::class);
+ $result = $accessor->subscribeMethods(ProfileVisited::class);
- self::assertEquals([
- $subscriber->onProfileCreated(...),
- ], $result);
+ self::assertArrayHasKey(0, $result);
+
+ $message = new Message(new ProfileVisited(ProfileId::fromString('1')));
+
+ $result[0]($message);
+
+ self::assertSame($message, $subscriber->message);
}
public function testMultipleSubscribeMethod(): void
@@ -114,6 +125,8 @@ public function onFoo(Message $message): void
$result = $accessor->subscribeMethods(ProfileCreated::class);
+ self::assertCount(2, $result);
+
self::assertEquals([
$subscriber->onProfileCreated(...),
$subscriber->onFoo(...),
@@ -124,9 +137,12 @@ public function testSubscribeAllMethod(): void
{
$subscriber = new #[Subscriber('profile', RunMode::FromBeginning)]
class {
+ public Message|null $message = null;
+
#[Subscribe('*')]
- public function onProfileCreated(Message $message): void
+ public function on(Message $message): void
{
+ $this->message = $message;
}
};
@@ -138,11 +154,69 @@ public function onProfileCreated(Message $message): void
],
);
- $result = $accessor->subscribeMethods(ProfileCreated::class);
+ $result = $accessor->subscribeMethods(ProfileVisited::class);
- self::assertEquals([
- $subscriber->onProfileCreated(...),
- ], $result);
+ self::assertArrayHasKey(0, $result);
+
+ $message = new Message(new ProfileVisited(ProfileId::fromString('1')));
+
+ $result[0]($message);
+
+ self::assertSame($message, $subscriber->message);
+ }
+
+ public function testNoResolver(): void
+ {
+ $this->expectException(NoSuitableResolver::class);
+
+ $subscriber = new #[Subscriber('profile', RunMode::FromBeginning)]
+ class {
+ #[Subscribe(ProfileVisited::class)]
+ public function on(Message $message): void
+ {
+ }
+ };
+
+ $accessor = new MetadataSubscriberAccessor(
+ $subscriber,
+ (new AttributeSubscriberMetadataFactory())->metadata($subscriber::class),
+ [],
+ );
+
+ $accessor->subscribeMethods(ProfileVisited::class);
+ }
+
+ public function testMultipleResolver(): void
+ {
+ $subscriber = new #[Subscriber('profile', RunMode::FromBeginning)]
+ class {
+ public Message|null $message = null;
+
+ #[Subscribe(ProfileVisited::class)]
+ public function on(Message $message): void
+ {
+ $this->message = $message;
+ }
+ };
+
+ $accessor = new MetadataSubscriberAccessor(
+ $subscriber,
+ (new AttributeSubscriberMetadataFactory())->metadata($subscriber::class),
+ [
+ new EventArgumentResolver(),
+ new MessageArgumentResolver(),
+ ],
+ );
+
+ $result = $accessor->subscribeMethods(ProfileVisited::class);
+
+ self::assertArrayHasKey(0, $result);
+
+ $message = new Message(new ProfileVisited(ProfileId::fromString('1')));
+
+ $result[0]($message);
+
+ self::assertSame($message, $subscriber->message);
}
public function testSetupMethod(): void