diff --git a/src/Messenger/Kernel/AutowiredHandlerLocator.php b/src/Messenger/Kernel/AutowiredHandlerLocator.php index 504a7de..eaafb6b 100644 --- a/src/Messenger/Kernel/AutowiredHandlerLocator.php +++ b/src/Messenger/Kernel/AutowiredHandlerLocator.php @@ -4,6 +4,7 @@ namespace WonderNetwork\SlimKernel\Messenger\Kernel; +use Psr\Container\ContainerInterface; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Handler\HandlerDescriptor; use Symfony\Component\Messenger\Handler\HandlersLocatorInterface; @@ -11,23 +12,27 @@ final readonly class AutowiredHandlerLocator implements HandlersLocatorInterface { /** - * @var array + * @var array */ private array $handlers; /** * @param array $handlers */ - public function __construct(array $handlers) { + public function __construct(private ContainerInterface $container, array $handlers) { $this->handlers = collection($handlers)->indexBy(new HandlerToMessageMapping())->toArray(); } public function getHandlers(Envelope $envelope): iterable { $class = $envelope->getMessage()::class; - $handler = $this->handlers[$class] ?? null; + $handlerClass = $this->handlers[$class] ?? null; - if ($handler) { - yield new HandlerDescriptor($handler); + if ($handlerClass) { + $handler = $this->container->get($handlerClass); + + if (is_callable($handler)) { + yield new HandlerDescriptor($handler); + } } } } diff --git a/src/Messenger/Kernel/HandlerToMessageMapping.php b/src/Messenger/Kernel/HandlerToMessageMapping.php index 43c75d8..03799fe 100644 --- a/src/Messenger/Kernel/HandlerToMessageMapping.php +++ b/src/Messenger/Kernel/HandlerToMessageMapping.php @@ -4,10 +4,10 @@ namespace WonderNetwork\SlimKernel\Messenger\Kernel; +use ReflectionClass; use ReflectionException; use ReflectionIntersectionType; use ReflectionNamedType; -use ReflectionObject; use ReflectionUnionType; use RuntimeException; @@ -15,8 +15,8 @@ /** * @throws ReflectionException */ - public function __invoke(mixed $handler): string { - if (false === is_object($handler)) { + public function __invoke(string $handler): string { + if (false === class_exists($handler)) { throw new RuntimeException( sprintf( 'Handler must be an object, %s given', @@ -25,13 +25,13 @@ public function __invoke(mixed $handler): string { ); } - $reflectionObject = new ReflectionObject($handler); + $reflectionObject = new ReflectionClass($handler); if (false === $reflectionObject->hasMethod('__invoke')) { throw new RuntimeException( sprintf( 'Handler %s does not have an __invoke method', - $handler::class, + $handler, ), ); } @@ -42,7 +42,7 @@ public function __invoke(mixed $handler): string { throw new RuntimeException( sprintf( 'Handler %s::__invoke() is expected to have exactly one parameter, actual: %d', - $handler::class, + $handler, $reflectionMethod->getNumberOfParameters(), ), ); @@ -52,11 +52,11 @@ public function __invoke(mixed $handler): string { return match (true) { $type instanceof ReflectionNamedType => $type->getName(), - $type instanceof ReflectionUnionType => $this->handleUnionTypes($handler::class, ...$type->getTypes()), + $type instanceof ReflectionUnionType => $this->handleUnionTypes($handler, ...$type->getTypes()), default => throw new RuntimeException( sprintf( 'Handler %s::__invoke($message) is not properly typehinted', - $handler::class, + $handler, ), ), }; diff --git a/src/Messenger/Kernel/MessengerServiceFactory.php b/src/Messenger/Kernel/MessengerServiceFactory.php index 1e73435..5728522 100644 --- a/src/Messenger/Kernel/MessengerServiceFactory.php +++ b/src/Messenger/Kernel/MessengerServiceFactory.php @@ -53,10 +53,10 @@ public function __invoke(ServicesBuilder $builder): iterable { yield from $commands = $builder->autowire()->glob($this->commandPath); yield from $queries = $builder->autowire()->glob($this->queryPath); yield AutowiredHandlerLocator::class => autowire() - ->constructor([ - ...collection($commands)->keys()->map(static fn (string $className) => get($className)), - ...collection($queries)->keys()->map(static fn (string $className) => get($className)), - ]); + ->constructor( + get(ContainerInterface::class), + collection($commands)->concat($queries)->keys()->toArray(), + ); yield HandlersLocatorInterface::class => get(AutowiredHandlerLocator::class); yield HandleMessageMiddleware::class => autowire()->constructor( handlersLocator: get(HandlersLocatorInterface::class), diff --git a/tests/Messenger/MessengerTest.php b/tests/Messenger/MessengerTest.php index 8507020..0d78497 100644 --- a/tests/Messenger/MessengerTest.php +++ b/tests/Messenger/MessengerTest.php @@ -4,8 +4,8 @@ namespace WonderNetwork\SlimKernel\Messenger; -use Acme\SideEffectsCommand; -use Acme\StateQuery; +use Acme\Sample\SideEffectsCommand; +use Acme\Sample\StateQuery; use PHPUnit\Framework\TestCase; use RuntimeException; use Symfony\Component\Console\Input\ArrayInput; @@ -32,8 +32,8 @@ public function testMessenger(): void { ->useCache(__DIR__.'/../../.cache/') ->register( new MessengerServiceFactory( - commandPath: 'src/*AsyncHandler.php', - queryPath: 'src/*QueryHandler.php', + commandPath: 'src/Sample/*AsyncHandler.php', + queryPath: 'src/Sample/*QueryHandler.php', transports: TransportLocatorBuilder::start() ->withTransport( name: $transportName, @@ -66,4 +66,19 @@ public function testMessenger(): void { self::assertSame($some, $queryBus->query(new StateQuery())); } + + public function testHandlersCanDependOnCommandBus(): void { + $root = realpath(__DIR__.'/../Resources/Messenger') ?: throw new RuntimeException('Oops'); + $container = KernelBuilder::start($root) + ->register( + new MessengerServiceFactory( + commandPath: 'src/Requeue/*Handler.php', + queryPath: 'src/Requeue/*QueryHandler.php', + ), + ) + ->build(); + + $this->expectNotToPerformAssertions(); + $container->get(CommandBus::class); + } } diff --git a/tests/Resources/Messenger/src/Requeue/RetryCommand.php b/tests/Resources/Messenger/src/Requeue/RetryCommand.php new file mode 100644 index 0000000..7748509 --- /dev/null +++ b/tests/Resources/Messenger/src/Requeue/RetryCommand.php @@ -0,0 +1,10 @@ + + */ +final readonly class RetryCommandHandler implements AsyncCommandHandler { + public function __construct(private CommandBus $commandBus) { + } + + public function __invoke(RetryCommand|AsyncCommand $command): void { + $this->commandBus->delay( + command: $command, + transport: 'some', + delay: Delay::ofHours(1), + ); + } +} diff --git a/tests/Resources/Messenger/src/SideEffectsAsyncHandler.php b/tests/Resources/Messenger/src/Sample/SideEffectsAsyncHandler.php similarity index 95% rename from tests/Resources/Messenger/src/SideEffectsAsyncHandler.php rename to tests/Resources/Messenger/src/Sample/SideEffectsAsyncHandler.php index d49f8ce..675f42c 100644 --- a/tests/Resources/Messenger/src/SideEffectsAsyncHandler.php +++ b/tests/Resources/Messenger/src/Sample/SideEffectsAsyncHandler.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Acme; +namespace Acme\Sample; use WonderNetwork\SlimKernel\Messenger\AsyncCommand; use WonderNetwork\SlimKernel\Messenger\AsyncCommandHandler; diff --git a/tests/Resources/Messenger/src/SideEffectsCommand.php b/tests/Resources/Messenger/src/Sample/SideEffectsCommand.php similarity index 91% rename from tests/Resources/Messenger/src/SideEffectsCommand.php rename to tests/Resources/Messenger/src/Sample/SideEffectsCommand.php index 58758c2..bf4d386 100644 --- a/tests/Resources/Messenger/src/SideEffectsCommand.php +++ b/tests/Resources/Messenger/src/Sample/SideEffectsCommand.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Acme; +namespace Acme\Sample; use WonderNetwork\SlimKernel\Messenger\AsyncCommand; diff --git a/tests/Resources/Messenger/src/StateQuery.php b/tests/Resources/Messenger/src/Sample/StateQuery.php similarity index 88% rename from tests/Resources/Messenger/src/StateQuery.php rename to tests/Resources/Messenger/src/Sample/StateQuery.php index 1f05d78..c6dcf86 100644 --- a/tests/Resources/Messenger/src/StateQuery.php +++ b/tests/Resources/Messenger/src/Sample/StateQuery.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Acme; +namespace Acme\Sample; use WonderNetwork\SlimKernel\Messenger\Query; diff --git a/tests/Resources/Messenger/src/StateQueryHandler.php b/tests/Resources/Messenger/src/Sample/StateQueryHandler.php similarity index 95% rename from tests/Resources/Messenger/src/StateQueryHandler.php rename to tests/Resources/Messenger/src/Sample/StateQueryHandler.php index ca3e0a1..d8ac67c 100644 --- a/tests/Resources/Messenger/src/StateQueryHandler.php +++ b/tests/Resources/Messenger/src/Sample/StateQueryHandler.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Acme; +namespace Acme\Sample; use WonderNetwork\SlimKernel\Messenger\HoldsState; use WonderNetwork\SlimKernel\Messenger\Query;