diff --git a/baseline.xml b/baseline.xml
index 029540042..22ff0c1fe 100644
--- a/baseline.xml
+++ b/baseline.xml
@@ -115,15 +115,14 @@
+
+
+
-
- subscriber->$method(...)]]>
-
-
@@ -134,7 +133,6 @@
-
@@ -142,7 +140,6 @@
-
@@ -151,7 +148,6 @@
-
@@ -163,7 +159,6 @@
id]]>
-
@@ -171,7 +166,6 @@
-
@@ -202,13 +196,6 @@
-
-
-
-
-
-
-
@@ -291,13 +278,6 @@
-
-
-
-
-
-
-
diff --git a/deptrac.yaml b/deptrac.yaml
index 9f94d591b..95e5c60a1 100644
--- a/deptrac.yaml
+++ b/deptrac.yaml
@@ -143,6 +143,7 @@ deptrac:
- Metadata
- Subscription
Subscription:
+ - Aggregate
- Attribute
- Clock
- Message
diff --git a/src/Metadata/Subscriber/ArgumentMetadata.php b/src/Metadata/Subscriber/ArgumentMetadata.php
new file mode 100644
index 000000000..56576fdba
--- /dev/null
+++ b/src/Metadata/Subscriber/ArgumentMetadata.php
@@ -0,0 +1,14 @@
+newInstance();
$eventClass = $instance->eventClass;
- $subscribeMethods[$eventClass][] = $method->getName();
+ $subscribeMethods[$eventClass][] = $this->subscribeMethod($method);
}
if ($method->getAttributes(Setup::class)) {
@@ -91,4 +94,27 @@ 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 instanceof ReflectionNamedType) {
+ throw new RuntimeException('parameter type is required');
+ }
+
+ $arguments[] = new ArgumentMetadata(
+ $parameter->getName(),
+ $type->getName(),
+ );
+ }
+
+ return new SubscribeMethodMetadata(
+ $method->getName(),
+ $arguments,
+ );
+ }
}
diff --git a/src/Metadata/Subscriber/SubscribeMethodMetadata.php b/src/Metadata/Subscriber/SubscribeMethodMetadata.php
new file mode 100644
index 000000000..aafcd7277
--- /dev/null
+++ b/src/Metadata/Subscriber/SubscribeMethodMetadata.php
@@ -0,0 +1,15 @@
+ $arguments */
+ public function __construct(
+ public readonly string $name,
+ public readonly array $arguments = [],
+ ) {
+ }
+}
diff --git a/src/Metadata/Subscriber/SubscriberMetadata.php b/src/Metadata/Subscriber/SubscriberMetadata.php
index e6335d795..8c26b1942 100644
--- a/src/Metadata/Subscriber/SubscriberMetadata.php
+++ b/src/Metadata/Subscriber/SubscriberMetadata.php
@@ -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> */
+ /** @var array> */
public readonly array $subscribeMethods = [],
public readonly string|null $setupMethod = null,
public readonly string|null $teardownMethod = null,
diff --git a/src/Subscription/Subscriber/ArgumentResolver/AggregateIdArgumentResolver.php b/src/Subscription/Subscriber/ArgumentResolver/AggregateIdArgumentResolver.php
new file mode 100644
index 000000000..3814fb172
--- /dev/null
+++ b/src/Subscription/Subscriber/ArgumentResolver/AggregateIdArgumentResolver.php
@@ -0,0 +1,24 @@
+header(AggregateHeader::class)->aggregateId;
+ }
+
+ public function support(ArgumentMetadata $argument, string $eventClass): bool
+ {
+ return $argument->type === 'string' && in_array($argument->name, ['aggregateId', 'aggregateRootId']);
+ }
+}
diff --git a/src/Subscription/Subscriber/ArgumentResolver/ArgumentResolver.php b/src/Subscription/Subscriber/ArgumentResolver/ArgumentResolver.php
new file mode 100644
index 000000000..2f0411af2
--- /dev/null
+++ b/src/Subscription/Subscriber/ArgumentResolver/ArgumentResolver.php
@@ -0,0 +1,15 @@
+event();
+ }
+
+ public function support(ArgumentMetadata $argument, string $eventClass): bool
+ {
+ return class_exists($argument->type) && is_a($eventClass, $argument->type, true);
+ }
+}
diff --git a/src/Subscription/Subscriber/ArgumentResolver/MessageArgumentResolver.php b/src/Subscription/Subscriber/ArgumentResolver/MessageArgumentResolver.php
new file mode 100644
index 000000000..ceabce7c8
--- /dev/null
+++ b/src/Subscription/Subscriber/ArgumentResolver/MessageArgumentResolver.php
@@ -0,0 +1,21 @@
+type === Message::class;
+ }
+}
diff --git a/src/Subscription/Subscriber/ArgumentResolver/RecordedOnArgumentResolver.php b/src/Subscription/Subscriber/ArgumentResolver/RecordedOnArgumentResolver.php
new file mode 100644
index 000000000..2a2e7dc45
--- /dev/null
+++ b/src/Subscription/Subscriber/ArgumentResolver/RecordedOnArgumentResolver.php
@@ -0,0 +1,23 @@
+header(AggregateHeader::class)->recordedOn;
+ }
+
+ public function support(ArgumentMetadata $argument, string $eventClass): bool
+ {
+ return $argument->type === DateTimeImmutable::class;
+ }
+}
diff --git a/src/Subscription/Subscriber/MetadataSubscriberAccessor.php b/src/Subscription/Subscriber/MetadataSubscriberAccessor.php
index c55f6c571..32cd948c6 100644
--- a/src/Subscription/Subscriber/MetadataSubscriberAccessor.php
+++ b/src/Subscription/Subscriber/MetadataSubscriberAccessor.php
@@ -7,8 +7,10 @@
use Closure;
use Patchlevel\EventSourcing\Attribute\Subscribe;
use Patchlevel\EventSourcing\Message\Message;
+use Patchlevel\EventSourcing\Metadata\Subscriber\SubscribeMethodMetadata;
use Patchlevel\EventSourcing\Metadata\Subscriber\SubscriberMetadata;
use Patchlevel\EventSourcing\Subscription\RunMode;
+use Patchlevel\EventSourcing\Subscription\Subscriber\ArgumentResolver\ArgumentResolver;
use function array_key_exists;
use function array_map;
@@ -19,9 +21,11 @@ final class MetadataSubscriberAccessor implements SubscriberAccessor
/** @var array> */
private array $subscribeCache = [];
+ /** @param list $argumentResolvers */
public function __construct(
private readonly object $subscriber,
private readonly SubscriberMetadata $metadata,
+ private readonly array $argumentResolvers,
) {
}
@@ -79,11 +83,59 @@ public function subscribeMethods(string $eventClass): array
);
$this->subscribeCache[$eventClass] = array_map(
- /** @return Closure(Message):void */
- fn (string $method) => $this->subscriber->$method(...),
+ fn (SubscribeMethodMetadata $method): Closure => $this->createClosure($eventClass, $method),
$methods,
);
return $this->subscribeCache[$eventClass];
}
+
+ /**
+ * @param class-string $eventClass
+ *
+ * @return Closure(Message):void
+ */
+ private function createClosure(string $eventClass, SubscribeMethodMetadata $method): Closure
+ {
+ $resolvers = $this->resolvers($eventClass, $method);
+ $methodName = $method->name;
+
+ return function (Message $message) use ($methodName, $resolvers): void {
+ $arguments = [];
+
+ foreach ($resolvers as $resolver) {
+ $arguments[] = $resolver($message);
+ }
+
+ $this->subscriber->$methodName(...$arguments);
+ };
+ }
+
+ /**
+ * @param class-string $eventClass
+ *
+ * @return list
+ */
+ private function resolvers(string $eventClass, SubscribeMethodMetadata $method): array
+ {
+ $resolvers = [];
+
+ foreach ($method->arguments as $argument) {
+ foreach ($this->argumentResolvers as $resolver) {
+ if (!$resolver->support($argument, $eventClass)) {
+ continue;
+ }
+
+ $resolvers[] = static function (Message $message) use ($resolver, $argument): mixed {
+ return $resolver->resolve($argument, $message);
+ };
+
+ continue 2;
+ }
+
+ throw new NoSuitableResolver($this->subscriber::class, $method->name, $argument->name);
+ }
+
+ return $resolvers;
+ }
}
diff --git a/src/Subscription/Subscriber/MetadataSubscriberAccessorRepository.php b/src/Subscription/Subscriber/MetadataSubscriberAccessorRepository.php
index 324c1eada..d38c6c974 100644
--- a/src/Subscription/Subscriber/MetadataSubscriberAccessorRepository.php
+++ b/src/Subscription/Subscriber/MetadataSubscriberAccessorRepository.php
@@ -6,7 +6,13 @@
use Patchlevel\EventSourcing\Metadata\Subscriber\AttributeSubscriberMetadataFactory;
use Patchlevel\EventSourcing\Metadata\Subscriber\SubscriberMetadataFactory;
+use Patchlevel\EventSourcing\Subscription\Subscriber\ArgumentResolver\AggregateIdArgumentResolver;
+use Patchlevel\EventSourcing\Subscription\Subscriber\ArgumentResolver\ArgumentResolver;
+use Patchlevel\EventSourcing\Subscription\Subscriber\ArgumentResolver\EventArgumentResolver;
+use Patchlevel\EventSourcing\Subscription\Subscriber\ArgumentResolver\MessageArgumentResolver;
+use Patchlevel\EventSourcing\Subscription\Subscriber\ArgumentResolver\RecordedOnArgumentResolver;
+use function array_merge;
use function array_values;
final class MetadataSubscriberAccessorRepository implements SubscriberAccessorRepository
@@ -14,11 +20,27 @@ final class MetadataSubscriberAccessorRepository implements SubscriberAccessorRe
/** @var array */
private array $subscribersMap = [];
- /** @param iterable