Skip to content

Navigation Menu

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 0d569f6

Browse filesBrowse files
committed
[Messenger] Compile time errors fixes and tweaks
1 parent 54305d6 commit 0d569f6
Copy full SHA for 0d569f6

File tree

2 files changed

+186
-13
lines changed
Filter options

2 files changed

+186
-13
lines changed

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php
+11-13Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,12 @@ private function registerHandlers(ContainerBuilder $container)
6161

6262
foreach ($container->findTaggedServiceIds($this->handlerTag, true) as $serviceId => $tags) {
6363
foreach ($tags as $tag) {
64-
$handles = $tag['handles'] ?? $this->guessHandledClass($container, $serviceId);
64+
$handles = $tag['handles'] ?? $this->guessHandledClass($r = $container->getReflectionClass($container->getDefinition($serviceId)->getClass()), $serviceId);
6565

6666
if (!class_exists($handles)) {
67-
$messageClassLocation = isset($tag['handles']) ? 'declared in your tag attribute "handles"' : 'declared in `__invoke` function';
67+
$messageClassLocation = isset($tag['handles']) ? 'declared in your tag attribute "handles"' : sprintf('used as argument type in method "%s::__invoke()"', $r->getName());
6868

69-
throw new RuntimeException(sprintf('The message class "%s" %s of service "%s" does not exist.', $messageClassLocation, $handles, $serviceId));
69+
throw new RuntimeException(sprintf('Invalid service "%s": message class "%s" %s does not exist.', $serviceId, $handles, $messageClassLocation));
7070
}
7171

7272
$priority = $tag['priority'] ?? 0;
@@ -102,27 +102,25 @@ private function registerHandlers(ContainerBuilder $container)
102102
$handlerResolver->replaceArgument(0, ServiceLocatorTagPass::register($container, $handlersLocatorMapping));
103103
}
104104

105-
private function guessHandledClass(ContainerBuilder $container, string $serviceId): string
105+
private function guessHandledClass(\ReflectionClass $handlerClass, string $serviceId): string
106106
{
107-
$reflection = $container->getReflectionClass($container->getDefinition($serviceId)->getClass());
108-
109107
try {
110-
$method = $reflection->getMethod('__invoke');
108+
$method = $handlerClass->getMethod('__invoke');
111109
} catch (\ReflectionException $e) {
112-
throw new RuntimeException(sprintf('Service "%s" should have an `__invoke` function.', $serviceId));
110+
throw new RuntimeException(sprintf('Invalid service "%s": class "%s" must have an "__invoke()" method.', $serviceId, $handlerClass->getName()));
113111
}
114112

115113
$parameters = $method->getParameters();
116114
if (1 !== count($parameters)) {
117-
throw new RuntimeException(sprintf('`__invoke` function of service "%s" must have exactly one parameter.', $serviceId));
115+
throw new RuntimeException(sprintf('Invalid service "%s": method "%s::__invoke()" must have exactly one argument corresponding to the message it handles.', $serviceId, $handlerClass->getName())
116+
);
118117
}
119118

120-
$parameter = $parameters[0];
121-
if (null === $parameter->getClass()) {
122-
throw new RuntimeException(sprintf('The parameter of `__invoke` function of service "%s" must type hint the message class it handles.', $serviceId));
119+
if (!$parameters[0]->hasType()) {
120+
throw new RuntimeException(sprintf('Invalid service "%s": argument of method "%s::__invoke()" must have a type-hint corresponding to the message class it handles.', $serviceId, $handlerClass->getName()));
123121
}
124122

125-
return $parameter->getClass()->getName();
123+
return $parameters[0]->getType();
126124
}
127125

128126
private function registerReceivers(ContainerBuilder $container)
+175Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
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\Tests\DependencyInjection;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
16+
use Symfony\Component\DependencyInjection\ContainerBuilder;
17+
use Symfony\Component\DependencyInjection\Reference;
18+
use Symfony\Component\DependencyInjection\ServiceLocator;
19+
use Symfony\Component\Messenger\ContainerHandlerLocator;
20+
use Symfony\Component\Messenger\DependencyInjection\MessengerPass;
21+
use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage;
22+
use Symfony\Component\Messenger\Transport\ReceiverInterface;
23+
24+
class MessengerPassTest extends TestCase
25+
{
26+
public function testProcess()
27+
{
28+
$container = $this->getContainerBuilder();
29+
$container
30+
->register(DummyHandler::class, DummyHandler::class)
31+
->addTag('message_handler')
32+
;
33+
$container
34+
->register(DummyReceiver::class, DummyReceiver::class)
35+
->addTag('messenger.receiver')
36+
;
37+
38+
(new MessengerPass())->process($container);
39+
40+
$handlerLocatorDefinition = $container->getDefinition($container->getDefinition('messenger.handler_resolver')->getArgument(0));
41+
$this->assertSame(ServiceLocator::class, $handlerLocatorDefinition->getClass());
42+
$this->assertEquals(
43+
array('handler.'.DummyMessage::class => new ServiceClosureArgument(new Reference(DummyHandler::class))),
44+
$handlerLocatorDefinition->getArgument(0)
45+
);
46+
47+
$this->assertEquals(
48+
array(DummyReceiver::class => new Reference(DummyReceiver::class)),
49+
$container->getDefinition('messenger.receiver_locator')->getArgument(0)
50+
);
51+
}
52+
53+
/**
54+
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
55+
* @expectedExceptionMessage Invalid 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.
56+
*/
57+
public function testUndefinedMessageClassForHandler()
58+
{
59+
$container = $this->getContainerBuilder();
60+
$container
61+
->register(UndefinedMessageHandler::class, UndefinedMessageHandler::class)
62+
->addTag('message_handler')
63+
;
64+
65+
(new MessengerPass())->process($container);
66+
}
67+
68+
/**
69+
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
70+
* @expectedExceptionMessage Invalid service "Symfony\Component\Messenger\Tests\DependencyInjection\NotInvokableHandler": class "Symfony\Component\Messenger\Tests\DependencyInjection\NotInvokableHandler" must have an "__invoke()" method.
71+
*/
72+
public function testNotInvokableHandler()
73+
{
74+
$container = $this->getContainerBuilder();
75+
$container
76+
->register(NotInvokableHandler::class, NotInvokableHandler::class)
77+
->addTag('message_handler')
78+
;
79+
80+
(new MessengerPass())->process($container);
81+
}
82+
83+
/**
84+
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
85+
* @expectedExceptionMessage Invalid service "Symfony\Component\Messenger\Tests\DependencyInjection\MissingArgumentHandler": method "Symfony\Component\Messenger\Tests\DependencyInjection\MissingArgumentHandler::__invoke()" must have exactly one argument corresponding to the message it handles.
86+
*/
87+
public function testMissingArgumentHandler()
88+
{
89+
$container = $this->getContainerBuilder();
90+
$container
91+
->register(MissingArgumentHandler::class, MissingArgumentHandler::class)
92+
->addTag('message_handler')
93+
;
94+
95+
(new MessengerPass())->process($container);
96+
}
97+
98+
/**
99+
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
100+
* @expectedExceptionMessage Invalid service "Symfony\Component\Messenger\Tests\DependencyInjection\MissingArgumentTypeHandler": argument of method "Symfony\Component\Messenger\Tests\DependencyInjection\MissingArgumentTypeHandler::__invoke()" must have a type-hint corresponding to the message class it handles.
101+
*/
102+
public function testMissingArgumentTypeHandler()
103+
{
104+
$container = $this->getContainerBuilder();
105+
$container
106+
->register(MissingArgumentTypeHandler::class, MissingArgumentTypeHandler::class)
107+
->addTag('message_handler')
108+
;
109+
110+
(new MessengerPass())->process($container);
111+
}
112+
113+
private function getContainerBuilder(): ContainerBuilder
114+
{
115+
$container = new ContainerBuilder();
116+
$container->setParameter('kernel.debug', true);
117+
118+
$container
119+
->register('message_bus', ContainerHandlerLocator::class)
120+
;
121+
122+
$container
123+
->register('messenger.handler_resolver', ContainerHandlerLocator::class)
124+
->addArgument(new Reference('service_container'))
125+
;
126+
127+
$container->register('messenger.receiver_locator', ServiceLocator::class)
128+
->addArgument(new Reference('service_container'))
129+
;
130+
131+
return $container;
132+
}
133+
}
134+
135+
class DummyHandler
136+
{
137+
public function __invoke(DummyMessage $message): void
138+
{
139+
}
140+
}
141+
142+
class DummyReceiver implements ReceiverInterface
143+
{
144+
public function receive(): iterable
145+
{
146+
for ($i = 0; $i < 3; ++$i) {
147+
yield new DummyMessage("Dummy $i");
148+
}
149+
}
150+
}
151+
152+
class UndefinedMessageHandler
153+
{
154+
public function __invoke(UndefinedMessage $message)
155+
{
156+
}
157+
}
158+
159+
class NotInvokableHandler
160+
{
161+
}
162+
163+
class MissingArgumentHandler
164+
{
165+
public function __invoke()
166+
{
167+
}
168+
}
169+
170+
class MissingArgumentTypeHandler
171+
{
172+
public function __invoke($message)
173+
{
174+
}
175+
}

0 commit comments

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