Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit a2f09cb

Browse filesBrowse files
committed
Enable auto-configuration for HandlerInterface
1 parent 2889acf commit a2f09cb
Copy full SHA for a2f09cb

File tree

Expand file treeCollapse file tree

4 files changed

+126
-9
lines changed
Filter options
Expand file treeCollapse file tree

4 files changed

+126
-9
lines changed

‎src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
use Symfony\Component\Lock\LockInterface;
6060
use Symfony\Component\Lock\Store\StoreFactory;
6161
use Symfony\Component\Lock\StoreInterface;
62+
use Symfony\Component\Messenger\Handler\HandlerInterface;
6263
use Symfony\Component\Messenger\Transport\ReceiverInterface;
6364
use Symfony\Component\Messenger\Transport\SenderInterface;
6465
use Symfony\Component\PropertyAccess\PropertyAccessor;
@@ -346,6 +347,8 @@ public function load(array $configs, ContainerBuilder $container)
346347
->addTag('messenger.receiver');
347348
$container->registerForAutoconfiguration(SenderInterface::class)
348349
->addTag('messenger.sender');
350+
$container->registerForAutoconfiguration(HandlerInterface::class)
351+
->addTag('messenger.message_handler');
349352

350353
if (!$container->getParameter('kernel.debug')) {
351354
// remove tagged iterator argument for resource checkers

‎src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php
+27-9Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
2020
use Symfony\Component\DependencyInjection\Reference;
2121
use Symfony\Component\Messenger\Handler\ChainHandler;
22+
use Symfony\Component\Messenger\Handler\HandlerInterface;
2223

2324
/**
2425
* @author Samuel Roze <samuel.roze@gmail.com>
@@ -67,16 +68,29 @@ private function registerHandlers(ContainerBuilder $container)
6768

6869
foreach ($container->findTaggedServiceIds($this->handlerTag, true) as $serviceId => $tags) {
6970
foreach ($tags as $tag) {
70-
$handles = $tag['handles'] ?? $this->guessHandledClass($r = $container->getReflectionClass($container->getParameterBag()->resolveValue($container->getDefinition($serviceId)->getClass())), $serviceId);
71-
72-
if (!class_exists($handles)) {
73-
$messageClassLocation = isset($tag['handles']) ? 'declared in your tag attribute "handles"' : sprintf('used as argument type in method "%s::__invoke()"', $r->getName());
74-
75-
throw new RuntimeException(sprintf('Invalid handler service "%s": message class "%s" %s does not exist.', $serviceId, $handles, $messageClassLocation));
71+
$handles = $tag['handles'] ?? $this->guessHandledClasses($r = $container->getReflectionClass($container->getParameterBag()->resolveValue($container->getDefinition($serviceId)->getClass())), $serviceId);
72+
if (empty($handles)) {
73+
throw new RuntimeException(sprintf('The handler service "%s" does not seem to handle any message.', $serviceId));
7674
}
7775

7876
$priority = $tag['priority'] ?? 0;
79-
$handlersByMessage[$handles][$priority][] = new Reference($serviceId);
77+
78+
foreach ($handles as $messageClass) {
79+
if (is_array($messageClass)) {
80+
$messagePriority = $messageClass[1];
81+
$messageClass = $messageClass[0];
82+
} else {
83+
$messagePriority = $priority;
84+
}
85+
86+
if (!class_exists($messageClass)) {
87+
$messageClassLocation = isset($tag['handles']) ? 'declared in your tag attribute "handles"' : sprintf('used as argument type in method "%s::__invoke()"', $r->getName());
88+
89+
throw new RuntimeException(sprintf('Invalid handler service "%s": message class "%s" %s does not exist.', $serviceId, $messageClass, $messageClassLocation));
90+
}
91+
92+
$handlersByMessage[$messageClass][$messagePriority][] = new Reference($serviceId);
93+
}
8094
}
8195
}
8296

@@ -108,8 +122,12 @@ private function registerHandlers(ContainerBuilder $container)
108122
$handlerResolver->replaceArgument(0, ServiceLocatorTagPass::register($container, $handlersLocatorMapping));
109123
}
110124

111-
private function guessHandledClass(\ReflectionClass $handlerClass, string $serviceId): string
125+
private function guessHandledClasses(\ReflectionClass $handlerClass, string $serviceId): array
112126
{
127+
if ($handlerClass->implementsInterface(HandlerInterface::class)) {
128+
return $handlerClass->getName()::getHandledMessages();
129+
}
130+
113131
try {
114132
$method = $handlerClass->getMethod('__invoke');
115133
} catch (\ReflectionException $e) {
@@ -129,7 +147,7 @@ private function guessHandledClass(\ReflectionClass $handlerClass, string $servi
129147
throw new RuntimeException(sprintf('Invalid handler service "%s": type-hint of argument "$%s" in method "%s::__invoke()" must be a class , "%s" given.', $serviceId, $parameters[0]->getName(), $handlerClass->getName(), $type));
130148
}
131149

132-
return $parameters[0]->getType();
150+
return array((string) $parameters[0]->getType());
133151
}
134152

135153
private function registerReceivers(ContainerBuilder $container)
+44Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Messenger\Handler;
13+
14+
/**
15+
* Handlers can implements this interface. This allows them to be auto-configured and to
16+
* handle multiple requests.
17+
*
18+
* @author Samuel Roze <samuel.roze@gmail.com>
19+
*/
20+
interface HandlerInterface
21+
{
22+
/**
23+
* Return a list of messages to be handled.
24+
*
25+
* It returns a list of messages like in the following example:
26+
*
27+
* return [
28+
* FirstMessage::class,
29+
* SecondMessage:class
30+
* ];
31+
*
32+
* It can also change the priority per classes.
33+
*
34+
* return [
35+
* [FirstMessage::class, 0],
36+
* [SecondMessage::class, -10],
37+
* ];
38+
*
39+
* The `__invoke` method of the handler will be called as usual with the message to handle.
40+
*
41+
* @return array
42+
*/
43+
public static function getHandledMessages(): array;
44+
}

‎src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php
+52Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@
1818
use Symfony\Component\DependencyInjection\ServiceLocator;
1919
use Symfony\Component\Messenger\ContainerHandlerLocator;
2020
use Symfony\Component\Messenger\DependencyInjection\MessengerPass;
21+
use Symfony\Component\Messenger\Handler\ChainHandler;
22+
use Symfony\Component\Messenger\Handler\HandlerInterface;
2123
use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage;
24+
use Symfony\Component\Messenger\Tests\Fixtures\SecondMessage;
2225
use Symfony\Component\Messenger\Transport\ReceiverInterface;
2326

2427
class MessengerPassTest extends TestCase
@@ -50,6 +53,34 @@ public function testProcess()
5053
);
5154
}
5255

56+
public function testGetClassesFromTheHandlerInterface()
57+
{
58+
$container = $this->getContainerBuilder();
59+
$container
60+
->register(HandlerWithMultipleMessages::class, HandlerWithMultipleMessages::class)
61+
->addTag('messenger.message_handler')
62+
;
63+
$container
64+
->register(PrioritisedHandler::class, PrioritisedHandler::class)
65+
->addTag('messenger.message_handler')
66+
;
67+
68+
(new MessengerPass())->process($container);
69+
70+
$handlerLocatorDefinition = $container->getDefinition($container->getDefinition('messenger.handler_resolver')->getArgument(0));
71+
$handlerMapping = $handlerLocatorDefinition->getArgument(0);
72+
73+
$this->assertArrayHasKey('handler.'.DummyMessage::class, $handlerMapping);
74+
$this->assertEquals(new ServiceClosureArgument(new Reference(HandlerWithMultipleMessages::class)), $handlerMapping['handler.'.DummyMessage::class]);
75+
76+
$this->assertArrayHasKey('handler.'.SecondMessage::class, $handlerMapping);
77+
$handlerReference = (string) $handlerMapping['handler.'.SecondMessage::class]->getValues()[0];
78+
$definition = $container->getDefinition($handlerReference);
79+
80+
$this->assertEquals(ChainHandler::class, $definition->getClass());
81+
$this->assertEquals(array(new Reference(PrioritisedHandler::class), new Reference(HandlerWithMultipleMessages::class)), $definition->getArgument(0));
82+
}
83+
5384
/**
5485
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
5586
* @expectedExceptionMessage Invalid handler service "Symfony\Component\Messenger\Tests\DependencyInjection\UndefinedMessageHandler": message class "Symfony\Component\Messenger\Tests\DependencyInjection\UndefinedMessage" used as argument type in method "Symfony\Component\Messenger\Tests\DependencyInjection\UndefinedMessageHandler::__invoke()" does not exist.
@@ -192,3 +223,24 @@ public function __invoke(string $message)
192223
{
193224
}
194225
}
226+
227+
class HandlerWithMultipleMessages implements HandlerInterface
228+
{
229+
public static function getHandledMessages(): array
230+
{
231+
return array(
232+
DummyMessage::class,
233+
SecondMessage::class,
234+
);
235+
}
236+
}
237+
238+
class PrioritisedHandler implements HandlerInterface
239+
{
240+
public static function getHandledMessages(): array
241+
{
242+
return array(
243+
array(SecondMessage::class, 10),
244+
);
245+
}
246+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.