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 ecb629a

Browse filesBrowse files
committed
minor #26672 [Messenger] Compile-time errors fixes and tweaks (chalasr)
This PR was merged into the 4.1-dev branch. Discussion ---------- [Messenger] Compile-time errors fixes and tweaks | Q | A | ------------- | --- | Branch? | master | Bug fix? | no (master only) | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | n/a | License | MIT | Doc PR | n/a Commits ------- 2889acf [Messenger] Compile time errors fixes and tweaks
2 parents 9b6ed69 + 2889acf commit ecb629a
Copy full SHA for ecb629a

File tree

3 files changed

+209
-14
lines changed
Filter options

3 files changed

+209
-14
lines changed

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

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

6868
foreach ($container->findTaggedServiceIds($this->handlerTag, true) as $serviceId => $tags) {
6969
foreach ($tags as $tag) {
70-
$handles = $tag['handles'] ?? $this->guessHandledClass($container, $serviceId);
70+
$handles = $tag['handles'] ?? $this->guessHandledClass($r = $container->getReflectionClass($container->getParameterBag()->resolveValue($container->getDefinition($serviceId)->getClass())), $serviceId);
7171

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

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

7878
$priority = $tag['priority'] ?? 0;
@@ -108,27 +108,28 @@ private function registerHandlers(ContainerBuilder $container)
108108
$handlerResolver->replaceArgument(0, ServiceLocatorTagPass::register($container, $handlersLocatorMapping));
109109
}
110110

111-
private function guessHandledClass(ContainerBuilder $container, string $serviceId): string
111+
private function guessHandledClass(\ReflectionClass $handlerClass, string $serviceId): string
112112
{
113-
$reflection = $container->getReflectionClass($container->getDefinition($serviceId)->getClass());
114-
115113
try {
116-
$method = $reflection->getMethod('__invoke');
114+
$method = $handlerClass->getMethod('__invoke');
117115
} catch (\ReflectionException $e) {
118-
throw new RuntimeException(sprintf('Service "%s" should have an `__invoke` function.', $serviceId));
116+
throw new RuntimeException(sprintf('Invalid handler service "%s": class "%s" must have an "__invoke()" method.', $serviceId, $handlerClass->getName()));
119117
}
120118

121119
$parameters = $method->getParameters();
122120
if (1 !== count($parameters)) {
123-
throw new RuntimeException(sprintf('`__invoke` function of service "%s" must have exactly one parameter.', $serviceId));
121+
throw new RuntimeException(sprintf('Invalid handler service "%s": method "%s::__invoke()" must have exactly one argument corresponding to the message it handles.', $serviceId, $handlerClass->getName()));
122+
}
123+
124+
if (!$type = $parameters[0]->getType()) {
125+
throw new RuntimeException(sprintf('Invalid handler service "%s": argument "$%s" of method "%s::__invoke()" must have a type-hint corresponding to the message class it handles.', $serviceId, $parameters[0]->getName(), $handlerClass->getName()));
124126
}
125127

126-
$parameter = $parameters[0];
127-
if (null === $parameter->getClass()) {
128-
throw new RuntimeException(sprintf('The parameter of `__invoke` function of service "%s" must type hint the message class it handles.', $serviceId));
128+
if ($type->isBuiltin()) {
129+
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));
129130
}
130131

131-
return $parameter->getClass()->getName();
132+
return $parameters[0]->getType();
132133
}
133134

134135
private function registerReceivers(ContainerBuilder $container)
+194Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
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('messenger.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 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.
56+
*/
57+
public function testUndefinedMessageClassForHandler()
58+
{
59+
$container = $this->getContainerBuilder();
60+
$container
61+
->register(UndefinedMessageHandler::class, UndefinedMessageHandler::class)
62+
->addTag('messenger.message_handler')
63+
;
64+
65+
(new MessengerPass())->process($container);
66+
}
67+
68+
/**
69+
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
70+
* @expectedExceptionMessage Invalid handler 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('messenger.message_handler')
78+
;
79+
80+
(new MessengerPass())->process($container);
81+
}
82+
83+
/**
84+
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
85+
* @expectedExceptionMessage Invalid handler 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('messenger.message_handler')
93+
;
94+
95+
(new MessengerPass())->process($container);
96+
}
97+
98+
/**
99+
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
100+
* @expectedExceptionMessage Invalid handler service "Symfony\Component\Messenger\Tests\DependencyInjection\MissingArgumentTypeHandler": argument "$message" 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('messenger.message_handler')
108+
;
109+
110+
(new MessengerPass())->process($container);
111+
}
112+
113+
/**
114+
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
115+
* @expectedExceptionMessage Invalid handler service "Symfony\Component\Messenger\Tests\DependencyInjection\BuiltinArgumentTypeHandler": type-hint of argument "$message" in method "Symfony\Component\Messenger\Tests\DependencyInjection\BuiltinArgumentTypeHandler::__invoke()" must be a class , "string" given.
116+
*/
117+
public function testBuiltinArgumentTypeHandler()
118+
{
119+
$container = $this->getContainerBuilder();
120+
$container
121+
->register(BuiltinArgumentTypeHandler::class, BuiltinArgumentTypeHandler::class)
122+
->addTag('messenger.message_handler')
123+
;
124+
125+
(new MessengerPass())->process($container);
126+
}
127+
128+
private function getContainerBuilder(): ContainerBuilder
129+
{
130+
$container = new ContainerBuilder();
131+
$container->setParameter('kernel.debug', true);
132+
$container->register('message_bus', ContainerHandlerLocator::class);
133+
134+
$container
135+
->register('messenger.handler_resolver', ContainerHandlerLocator::class)
136+
->addArgument(new Reference('service_container'))
137+
;
138+
139+
$container->register('messenger.receiver_locator', ServiceLocator::class)
140+
->addArgument(new Reference('service_container'))
141+
;
142+
143+
return $container;
144+
}
145+
}
146+
147+
class DummyHandler
148+
{
149+
public function __invoke(DummyMessage $message): void
150+
{
151+
}
152+
}
153+
154+
class DummyReceiver implements ReceiverInterface
155+
{
156+
public function receive(): iterable
157+
{
158+
for ($i = 0; $i < 3; ++$i) {
159+
yield new DummyMessage("Dummy $i");
160+
}
161+
}
162+
}
163+
164+
class UndefinedMessageHandler
165+
{
166+
public function __invoke(UndefinedMessage $message)
167+
{
168+
}
169+
}
170+
171+
class NotInvokableHandler
172+
{
173+
}
174+
175+
class MissingArgumentHandler
176+
{
177+
public function __invoke()
178+
{
179+
}
180+
}
181+
182+
class MissingArgumentTypeHandler
183+
{
184+
public function __invoke($message)
185+
{
186+
}
187+
}
188+
189+
class BuiltinArgumentTypeHandler
190+
{
191+
public function __invoke(string $message)
192+
{
193+
}
194+
}

‎src/Symfony/Component/Messenger/composer.json

Copy file name to clipboardExpand all lines: src/Symfony/Component/Messenger/composer.json
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
},
2121
"require-dev": {
2222
"symfony/serializer": "~3.4|~4.0",
23-
"symfony/dependency-injection": "~3.4|~4.0",
23+
"symfony/dependency-injection": "~3.4.6|~4.0",
2424
"symfony/property-access": "~3.4|~4.0"
2525
},
2626
"suggest": {

0 commit comments

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