Skip to content

Commit 04d0ae3

Browse files
authored
Merge pull request #19 from WonderNetwork/feature/messenger
allow handlers to depend on the CommandBus
2 parents c6aece1 + 86f0c5e commit 04d0ae3

10 files changed

Lines changed: 81 additions & 25 deletions

File tree

src/Messenger/Kernel/AutowiredHandlerLocator.php

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,35 @@
44

55
namespace WonderNetwork\SlimKernel\Messenger\Kernel;
66

7+
use Psr\Container\ContainerInterface;
78
use Symfony\Component\Messenger\Envelope;
89
use Symfony\Component\Messenger\Handler\HandlerDescriptor;
910
use Symfony\Component\Messenger\Handler\HandlersLocatorInterface;
1011
use function WonderNetwork\SlimKernel\Collection\collection;
1112

1213
final readonly class AutowiredHandlerLocator implements HandlersLocatorInterface {
1314
/**
14-
* @var array<class-string, callable>
15+
* @var array<class-string, class-string>
1516
*/
1617
private array $handlers;
1718

1819
/**
1920
* @param array<callable> $handlers
2021
*/
21-
public function __construct(array $handlers) {
22+
public function __construct(private ContainerInterface $container, array $handlers) {
2223
$this->handlers = collection($handlers)->indexBy(new HandlerToMessageMapping())->toArray();
2324
}
2425

2526
public function getHandlers(Envelope $envelope): iterable {
2627
$class = $envelope->getMessage()::class;
27-
$handler = $this->handlers[$class] ?? null;
28+
$handlerClass = $this->handlers[$class] ?? null;
2829

29-
if ($handler) {
30-
yield new HandlerDescriptor($handler);
30+
if ($handlerClass) {
31+
$handler = $this->container->get($handlerClass);
32+
33+
if (is_callable($handler)) {
34+
yield new HandlerDescriptor($handler);
35+
}
3136
}
3237
}
3338
}

src/Messenger/Kernel/HandlerToMessageMapping.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,19 @@
44

55
namespace WonderNetwork\SlimKernel\Messenger\Kernel;
66

7+
use ReflectionClass;
78
use ReflectionException;
89
use ReflectionIntersectionType;
910
use ReflectionNamedType;
10-
use ReflectionObject;
1111
use ReflectionUnionType;
1212
use RuntimeException;
1313

1414
final readonly class HandlerToMessageMapping {
1515
/**
1616
* @throws ReflectionException
1717
*/
18-
public function __invoke(mixed $handler): string {
19-
if (false === is_object($handler)) {
18+
public function __invoke(string $handler): string {
19+
if (false === class_exists($handler)) {
2020
throw new RuntimeException(
2121
sprintf(
2222
'Handler must be an object, %s given',
@@ -25,13 +25,13 @@ public function __invoke(mixed $handler): string {
2525
);
2626
}
2727

28-
$reflectionObject = new ReflectionObject($handler);
28+
$reflectionObject = new ReflectionClass($handler);
2929

3030
if (false === $reflectionObject->hasMethod('__invoke')) {
3131
throw new RuntimeException(
3232
sprintf(
3333
'Handler %s does not have an __invoke method',
34-
$handler::class,
34+
$handler,
3535
),
3636
);
3737
}
@@ -42,7 +42,7 @@ public function __invoke(mixed $handler): string {
4242
throw new RuntimeException(
4343
sprintf(
4444
'Handler %s::__invoke() is expected to have exactly one parameter, actual: %d',
45-
$handler::class,
45+
$handler,
4646
$reflectionMethod->getNumberOfParameters(),
4747
),
4848
);
@@ -52,11 +52,11 @@ public function __invoke(mixed $handler): string {
5252

5353
return match (true) {
5454
$type instanceof ReflectionNamedType => $type->getName(),
55-
$type instanceof ReflectionUnionType => $this->handleUnionTypes($handler::class, ...$type->getTypes()),
55+
$type instanceof ReflectionUnionType => $this->handleUnionTypes($handler, ...$type->getTypes()),
5656
default => throw new RuntimeException(
5757
sprintf(
5858
'Handler %s::__invoke($message) is not properly typehinted',
59-
$handler::class,
59+
$handler,
6060
),
6161
),
6262
};

src/Messenger/Kernel/MessengerServiceFactory.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,10 @@ public function __invoke(ServicesBuilder $builder): iterable {
5353
yield from $commands = $builder->autowire()->glob($this->commandPath);
5454
yield from $queries = $builder->autowire()->glob($this->queryPath);
5555
yield AutowiredHandlerLocator::class => autowire()
56-
->constructor([
57-
...collection($commands)->keys()->map(static fn (string $className) => get($className)),
58-
...collection($queries)->keys()->map(static fn (string $className) => get($className)),
59-
]);
56+
->constructor(
57+
get(ContainerInterface::class),
58+
collection($commands)->concat($queries)->keys()->toArray(),
59+
);
6060
yield HandlersLocatorInterface::class => get(AutowiredHandlerLocator::class);
6161
yield HandleMessageMiddleware::class => autowire()->constructor(
6262
handlersLocator: get(HandlersLocatorInterface::class),

tests/Messenger/MessengerTest.php

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
namespace WonderNetwork\SlimKernel\Messenger;
66

7-
use Acme\SideEffectsCommand;
8-
use Acme\StateQuery;
7+
use Acme\Sample\SideEffectsCommand;
8+
use Acme\Sample\StateQuery;
99
use PHPUnit\Framework\TestCase;
1010
use RuntimeException;
1111
use Symfony\Component\Console\Input\ArrayInput;
@@ -32,8 +32,8 @@ public function testMessenger(): void {
3232
->useCache(__DIR__.'/../../.cache/')
3333
->register(
3434
new MessengerServiceFactory(
35-
commandPath: 'src/*AsyncHandler.php',
36-
queryPath: 'src/*QueryHandler.php',
35+
commandPath: 'src/Sample/*AsyncHandler.php',
36+
queryPath: 'src/Sample/*QueryHandler.php',
3737
transports: TransportLocatorBuilder::start()
3838
->withTransport(
3939
name: $transportName,
@@ -66,4 +66,19 @@ public function testMessenger(): void {
6666

6767
self::assertSame($some, $queryBus->query(new StateQuery()));
6868
}
69+
70+
public function testHandlersCanDependOnCommandBus(): void {
71+
$root = realpath(__DIR__.'/../Resources/Messenger') ?: throw new RuntimeException('Oops');
72+
$container = KernelBuilder::start($root)
73+
->register(
74+
new MessengerServiceFactory(
75+
commandPath: 'src/Requeue/*Handler.php',
76+
queryPath: 'src/Requeue/*QueryHandler.php',
77+
),
78+
)
79+
->build();
80+
81+
$this->expectNotToPerformAssertions();
82+
$container->get(CommandBus::class);
83+
}
6984
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Acme\Requeue;
6+
7+
use WonderNetwork\SlimKernel\Messenger\AsyncCommand;
8+
9+
final readonly class RetryCommand implements AsyncCommand {
10+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Acme\Requeue;
6+
7+
use WonderNetwork\SlimKernel\Messenger\AsyncCommand;
8+
use WonderNetwork\SlimKernel\Messenger\AsyncCommandHandler;
9+
use WonderNetwork\SlimKernel\Messenger\CommandBus;
10+
use WonderNetwork\SlimKernel\Messenger\Delay;
11+
12+
/**
13+
* @implements AsyncCommandHandler<RetryCommand>
14+
*/
15+
final readonly class RetryCommandHandler implements AsyncCommandHandler {
16+
public function __construct(private CommandBus $commandBus) {
17+
}
18+
19+
public function __invoke(RetryCommand|AsyncCommand $command): void {
20+
$this->commandBus->delay(
21+
command: $command,
22+
transport: 'some',
23+
delay: Delay::ofHours(1),
24+
);
25+
}
26+
}

tests/Resources/Messenger/src/SideEffectsAsyncHandler.php renamed to tests/Resources/Messenger/src/Sample/SideEffectsAsyncHandler.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
declare(strict_types=1);
44

5-
namespace Acme;
5+
namespace Acme\Sample;
66

77
use WonderNetwork\SlimKernel\Messenger\AsyncCommand;
88
use WonderNetwork\SlimKernel\Messenger\AsyncCommandHandler;

tests/Resources/Messenger/src/SideEffectsCommand.php renamed to tests/Resources/Messenger/src/Sample/SideEffectsCommand.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
declare(strict_types=1);
44

5-
namespace Acme;
5+
namespace Acme\Sample;
66

77
use WonderNetwork\SlimKernel\Messenger\AsyncCommand;
88

tests/Resources/Messenger/src/StateQuery.php renamed to tests/Resources/Messenger/src/Sample/StateQuery.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
declare(strict_types=1);
44

5-
namespace Acme;
5+
namespace Acme\Sample;
66

77
use WonderNetwork\SlimKernel\Messenger\Query;
88

tests/Resources/Messenger/src/StateQueryHandler.php renamed to tests/Resources/Messenger/src/Sample/StateQueryHandler.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
declare(strict_types=1);
44

5-
namespace Acme;
5+
namespace Acme\Sample;
66

77
use WonderNetwork\SlimKernel\Messenger\HoldsState;
88
use WonderNetwork\SlimKernel\Messenger\Query;

0 commit comments

Comments
 (0)