Skip to content

Commit 62d9634

Browse files
committed
Improve error message when defining messenger handler class that does not exists
1 parent 100f205 commit 62d9634

File tree

2 files changed

+106
-20
lines changed

2 files changed

+106
-20
lines changed

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

Lines changed: 90 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,11 @@ class MessengerPass implements CompilerPassInterface
3636
private $busTag;
3737
private $receiverTag;
3838

39-
public function __construct(string $handlerTag = 'messenger.message_handler', string $busTag = 'messenger.bus', string $receiverTag = 'messenger.receiver')
40-
{
39+
public function __construct(
40+
string $handlerTag = 'messenger.message_handler',
41+
string $busTag = 'messenger.bus',
42+
string $receiverTag = 'messenger.receiver'
43+
) {
4144
$this->handlerTag = $handlerTag;
4245
$this->busTag = $busTag;
4346
$this->receiverTag = $receiverTag;
@@ -76,15 +79,26 @@ private function registerHandlers(ContainerBuilder $container, array $busIds)
7679
foreach ($container->findTaggedServiceIds($this->handlerTag, true) as $serviceId => $tags) {
7780
foreach ($tags as $tag) {
7881
if (isset($tag['bus']) && !\in_array($tag['bus'], $busIds, true)) {
79-
throw new RuntimeException(sprintf('Invalid handler service "%s": bus "%s" specified on the tag "%s" does not exist (known ones are: %s).', $serviceId, $tag['bus'], $this->handlerTag, implode(', ', $busIds)));
82+
throw new RuntimeException(sprintf(
83+
'Invalid handler service "%s": bus "%s" specified on the tag "%s" does not exist (known ones are: %s).',
84+
$serviceId,
85+
$tag['bus'],
86+
$this->handlerTag,
87+
implode(', ', $busIds)
88+
));
8089
}
8190

82-
$r = $container->getReflectionClass($container->getDefinition($serviceId)->getClass());
91+
$className = $container->getDefinition($serviceId)->getClass();
92+
$classReflector = $container->getReflectionClass($className);
93+
94+
if (null === $classReflector) {
95+
throw new RuntimeException(sprintf('Invalid service "%s": class "%s" does not exist.', $serviceId, $className));
96+
}
8397

8498
if (isset($tag['handles'])) {
8599
$handles = isset($tag['method']) ? array($tag['handles'] => $tag['method']) : array($tag['handles']);
86100
} else {
87-
$handles = $this->guessHandledClasses($r, $serviceId);
101+
$handles = $this->guessHandledClasses($classReflector, $serviceId);
88102
}
89103

90104
$message = null;
@@ -106,9 +120,20 @@ private function registerHandlers(ContainerBuilder $container, array $busIds)
106120
if (\is_array($method)) {
107121
if (isset($method['bus'])) {
108122
if (!\in_array($method['bus'], $busIds)) {
109-
$messageLocation = isset($tag['handles']) ? 'declared in your tag attribute "handles"' : $r->implementsInterface(MessageSubscriberInterface::class) ? sprintf('returned by method "%s::getHandledMessages()"', $r->getName()) : sprintf('used as argument type in method "%s::%s()"', $r->getName(), $method);
110-
111-
throw new RuntimeException(sprintf('Invalid configuration %s for message "%s": bus "%s" does not exist.', $messageLocation, $message, $method['bus']));
123+
$messageLocation = isset($tag['handles'])
124+
? 'declared in your tag attribute "handles"'
125+
: (
126+
$classReflector->implementsInterface(MessageSubscriberInterface::class)
127+
? sprintf('returned by method "%s::getHandledMessages()"', $classReflector->getName())
128+
: sprintf('used as argument type in method "%s::%s()"', $classReflector->getName(), $method)
129+
);
130+
131+
throw new RuntimeException(sprintf(
132+
'Invalid configuration %s for message "%s": bus "%s" does not exist.',
133+
$messageLocation,
134+
$message,
135+
$method['bus']
136+
));
112137
}
113138

114139
$buses = array($method['bus']);
@@ -119,19 +144,36 @@ private function registerHandlers(ContainerBuilder $container, array $busIds)
119144
}
120145

121146
if ('*' !== $message && !class_exists($message) && !interface_exists($message, false)) {
122-
$messageLocation = isset($tag['handles']) ? 'declared in your tag attribute "handles"' : $r->implementsInterface(MessageSubscriberInterface::class) ? sprintf('returned by method "%s::getHandledMessages()"', $r->getName()) : sprintf('used as argument type in method "%s::%s()"', $r->getName(), $method);
123-
124-
throw new RuntimeException(sprintf('Invalid handler service "%s": class or interface "%s" %s not found.', $serviceId, $message, $messageLocation));
147+
$messageLocation = isset($tag['handles'])
148+
? 'declared in your tag attribute "handles"'
149+
: (
150+
$classReflector->implementsInterface(MessageSubscriberInterface::class)
151+
? sprintf('returned by method "%s::getHandledMessages()"', $classReflector->getName())
152+
: sprintf('used as argument type in method "%s::%s()"', $classReflector->getName(), $method)
153+
);
154+
155+
throw new RuntimeException(sprintf(
156+
'Invalid handler service "%s": class or interface "%s" %s not found.',
157+
$serviceId,
158+
$message,
159+
$messageLocation
160+
));
125161
}
126162

127-
if (!$r->hasMethod($method)) {
128-
throw new RuntimeException(sprintf('Invalid handler service "%s": method "%s::%s()" does not exist.', $serviceId, $r->getName(), $method));
163+
if (!$classReflector->hasMethod($method)) {
164+
throw new RuntimeException(sprintf(
165+
'Invalid handler service "%s": method "%s::%s()" does not exist.',
166+
$serviceId,
167+
$classReflector->getName(),
168+
$method
169+
));
129170
}
130171

131172
if ('__invoke' !== $method) {
132173
$wrapperDefinition = (new Definition('callable'))->addArgument(array(new Reference($serviceId), $method))->setFactory('Closure::fromCallable');
133174

134-
$definitions[$definitionId = '.messenger.method_on_object_wrapper.'.ContainerBuilder::hash($message.':'.$priority.':'.$serviceId.':'.$method)] = $wrapperDefinition;
175+
$definitionId = '.messenger.method_on_object_wrapper.'.ContainerBuilder::hash($message.':'.$priority.':'.$serviceId.':'.$method);
176+
$definitions[$definitionId] = $wrapperDefinition;
135177
} else {
136178
$definitionId = $serviceId;
137179
}
@@ -142,7 +184,11 @@ private function registerHandlers(ContainerBuilder $container, array $busIds)
142184
}
143185

144186
if (null === $message) {
145-
throw new RuntimeException(sprintf('Invalid handler service "%s": method "%s::getHandledMessages()" must return one or more messages.', $serviceId, $r->getName()));
187+
throw new RuntimeException(sprintf(
188+
'Invalid handler service "%s": method "%s::getHandledMessages()" must return one or more messages.',
189+
$serviceId,
190+
$classReflector->getName()
191+
));
146192
}
147193
}
148194
}
@@ -198,20 +244,39 @@ private function guessHandledClasses(\ReflectionClass $handlerClass, string $ser
198244
try {
199245
$method = $handlerClass->getMethod('__invoke');
200246
} catch (\ReflectionException $e) {
201-
throw new RuntimeException(sprintf('Invalid handler service "%s": class "%s" must have an "__invoke()" method.', $serviceId, $handlerClass->getName()));
247+
throw new RuntimeException(sprintf(
248+
'Invalid handler service "%s": class "%s" must have an "__invoke()" method.',
249+
$serviceId,
250+
$handlerClass->getName()
251+
));
202252
}
203253

204254
$parameters = $method->getParameters();
205255
if (1 !== \count($parameters)) {
206-
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()));
256+
throw new RuntimeException(sprintf(
257+
'Invalid handler service "%s": method "%s::__invoke()" must have exactly one argument corresponding to the message it handles.',
258+
$serviceId,
259+
$handlerClass->getName()
260+
));
207261
}
208262

209263
if (!$type = $parameters[0]->getType()) {
210-
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()));
264+
throw new RuntimeException(sprintf(
265+
'Invalid handler service "%s": argument "$%s" of method "%s::__invoke()" must have a type-hint corresponding to the message class it handles.',
266+
$serviceId,
267+
$parameters[0]->getName(),
268+
$handlerClass->getName()
269+
));
211270
}
212271

213272
if ($type->isBuiltin()) {
214-
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));
273+
throw new RuntimeException(sprintf(
274+
'Invalid handler service "%s": type-hint of argument "$%s" in method "%s::__invoke()" must be a class , "%s" given.',
275+
$serviceId,
276+
$parameters[0]->getName(),
277+
$handlerClass->getName(),
278+
$type
279+
));
215280
}
216281

217282
return array((string) $parameters[0]->getType());
@@ -224,7 +289,12 @@ private function registerReceivers(ContainerBuilder $container, array $busIds)
224289
foreach ($container->findTaggedServiceIds($this->receiverTag) as $id => $tags) {
225290
$receiverClass = $container->findDefinition($id)->getClass();
226291
if (!is_subclass_of($receiverClass, ReceiverInterface::class)) {
227-
throw new RuntimeException(sprintf('Invalid receiver "%s": class "%s" must implement interface "%s".', $id, $receiverClass, ReceiverInterface::class));
292+
throw new RuntimeException(sprintf(
293+
'Invalid receiver "%s": class "%s" must implement interface "%s".',
294+
$id,
295+
$receiverClass,
296+
ReceiverInterface::class
297+
));
228298
}
229299

230300
$receiverMapping[$id] = new Reference($id);

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,22 @@ public function testGetClassesAndMethodsAndPrioritiesFromTheSubscriber()
194194
$this->assertSame(PrioritizedHandler::class, $secondHandlerDefinition->getClass());
195195
}
196196

197+
/**
198+
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
199+
* @expectedExceptionMessage Invalid service "NonExistentHandlerClass": class "NonExistentHandlerClass" does not exist.
200+
*/
201+
public function testThrowsExceptionIfTheHandlerClassDoesNotExist()
202+
{
203+
$container = $this->getContainerBuilder();
204+
$container->register('message_bus', MessageBusInterface::class)->addTag('messenger.bus');
205+
$container
206+
->register('NonExistentHandlerClass', 'NonExistentHandlerClass')
207+
->addTag('messenger.message_handler')
208+
;
209+
210+
(new MessengerPass())->process($container);
211+
}
212+
197213
/**
198214
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
199215
* @expectedExceptionMessage Invalid handler service "Symfony\Component\Messenger\Tests\DependencyInjection\HandlerMappingWithNonExistentMethod": method "Symfony\Component\Messenger\Tests\DependencyInjection\HandlerMappingWithNonExistentMethod::dummyMethod()" does not exist.

0 commit comments

Comments
 (0)