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 2dfd136

Browse filesBrowse files
committed
minor #22135 [DI] Add hints to exceptions thrown by AutowiringPass (nicolas-grekas)
This PR was merged into the 3.3-dev branch. Discussion ---------- [DI] Add hints to exceptions thrown by AutowiringPass | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - As spotted while working on #22060 Commits ------- d7557cf [DI] Add hints to exceptions thrown by AutowiringPass
2 parents 2ad5923 + d7557cf commit 2dfd136
Copy full SHA for 2dfd136

File tree

2 files changed

+103
-38
lines changed
Filter options

2 files changed

+103
-38
lines changed

‎src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php
+68-28Lines changed: 68 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,13 @@ public function process(ContainerBuilder $container)
5050
continue;
5151
}
5252

53-
$classOrInterface = class_exists($type) ? 'class' : 'interface';
54-
$matchingServices = implode(', ', $this->ambiguousServiceTypes[$type]);
53+
$this->container = $container;
54+
$classOrInterface = class_exists($type, false) ? 'class' : 'interface';
5555

56-
throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s". Multiple services exist for this %s (%s).', $type, $id, $classOrInterface, $matchingServices));
56+
throw new RuntimeException(sprintf('Cannot autowire service "%s": multiple candidate services exist for %s "%s".%s', $id, $classOrInterface, $type, $this->createTypeAlternatives($type)));
5757
}
5858
} finally {
59-
// Free memory
59+
$this->container = null;
6060
$this->definedTypes = array();
6161
$this->types = null;
6262
$this->ambiguousServiceTypes = array();
@@ -108,7 +108,12 @@ protected function processValue($value, $isRoot = false)
108108
$this->currentDefinition = $value;
109109

110110
try {
111-
if (!$value->isAutowired() || !$reflectionClass = $this->container->getReflectionClass($value->getClass())) {
111+
if (!$value->isAutowired() || $value->isAbstract() || !$value->getClass()) {
112+
return parent::processValue($value, $isRoot);
113+
}
114+
if (!$reflectionClass = $this->container->getReflectionClass($value->getClass())) {
115+
$this->container->log($this, sprintf('Skipping service "%s": Class or interface "%s" does not exist.', $this->currentId, $value->getClass()));
116+
112117
return parent::processValue($value, $isRoot);
113118
}
114119

@@ -117,8 +122,6 @@ protected function processValue($value, $isRoot = false)
117122

118123
if ($constructor = $reflectionClass->getConstructor()) {
119124
array_unshift($methodCalls, array($constructor->name, $value->getArguments()));
120-
} elseif ($value->getArguments()) {
121-
throw new RuntimeException(sprintf('Cannot autowire service "%s": class %s has no constructor but arguments are defined.', $this->currentId, $reflectionClass->name));
122125
}
123126

124127
$methodCalls = $this->autowireCalls($reflectionClass, $methodCalls, $autowiredMethods);
@@ -203,11 +206,13 @@ private function autowireCalls(\ReflectionClass $reflectionClass, array $methodC
203206
unset($autowiredMethods[$lcMethod]);
204207
} else {
205208
if (!$reflectionClass->hasMethod($method)) {
206-
throw new RuntimeException(sprintf('Cannot autowire service "%s": method %s::%s() does not exist.', $this->currentId, $reflectionClass->name, $method));
209+
$class = $reflectionClass->name;
210+
throw new RuntimeException(sprintf('Cannot autowire service "%s": method %s() does not exist.', $this->currentId, $class !== $this->currentId ? $class.'::'.$method : $method));
207211
}
208212
$reflectionMethod = $reflectionClass->getMethod($method);
209213
if (!$reflectionMethod->isPublic()) {
210-
throw new RuntimeException(sprintf('Cannot autowire service "%s": method %s::%s() must be public.', $this->currentId, $reflectionClass->name, $method));
214+
$class = $reflectionClass->name;
215+
throw new RuntimeException(sprintf('Cannot autowire service "%s": method %s() must be public.', $this->currentId, $class !== $this->currentId ? $class.'::'.$method : $method));
211216
}
212217
}
213218

@@ -222,10 +227,13 @@ private function autowireCalls(\ReflectionClass $reflectionClass, array $methodC
222227
if (!$reflectionMethod->getNumberOfParameters()) {
223228
continue; // skip getters
224229
}
230+
$method = $reflectionMethod->name;
231+
225232
if (!$reflectionMethod->isPublic()) {
226-
throw new RuntimeException(sprintf('Cannot autowire service "%s": method %s::%s() must be public.', $this->currentId, $reflectionClass->name, $reflectionMethod->name));
233+
$class = $reflectionClass->name;
234+
throw new RuntimeException(sprintf('Cannot autowire service "%s": method %s() must be public.', $this->currentId, $class !== $this->currentId ? $class.'::'.$method : $method));
227235
}
228-
$methodCalls[] = array($reflectionMethod->name, $this->autowireMethod($reflectionMethod, array()));
236+
$methodCalls[] = array($method, $this->autowireMethod($reflectionMethod, array()));
229237
}
230238

231239
return $methodCalls;
@@ -244,9 +252,11 @@ private function autowireCalls(\ReflectionClass $reflectionClass, array $methodC
244252
private function autowireMethod(\ReflectionMethod $reflectionMethod, array $arguments)
245253
{
246254
$isConstructor = $reflectionMethod->isConstructor();
255+
$class = $reflectionMethod->class;
256+
$method = $reflectionMethod->name;
247257

248258
if (!$isConstructor && !$arguments && !$reflectionMethod->getNumberOfRequiredParameters()) {
249-
throw new RuntimeException(sprintf('Cannot autowire service "%s": method %s::%s() has only optional arguments, thus must be wired explicitly.', $this->currentId, $reflectionMethod->class, $reflectionMethod->name));
259+
throw new RuntimeException(sprintf('Cannot autowire service "%s": method %s() has only optional arguments, thus must be wired explicitly.', $this->currentId, $class !== $this->currentId ? $class.'::'.$method : $method));
250260
}
251261

252262
foreach ($reflectionMethod->getParameters() as $index => $parameter) {
@@ -265,7 +275,7 @@ private function autowireMethod(\ReflectionMethod $reflectionMethod, array $argu
265275
if (!$type) {
266276
// no default value? Then fail
267277
if (!$parameter->isOptional()) {
268-
throw new RuntimeException(sprintf('Cannot autowire service "%s": argument $%s of method %s::%s() must have a type-hint or be given a value explicitly.', $this->currentId, $parameter->name, $reflectionMethod->class, $reflectionMethod->name));
278+
throw new RuntimeException(sprintf('Cannot autowire service "%s": argument $%s of method %s() must have a type-hint or be given a value explicitly.', $this->currentId, $parameter->name, $class !== $this->currentId ? $class.'::'.$method : $method));
269279
}
270280

271281
if (!array_key_exists($index, $arguments)) {
@@ -279,7 +289,7 @@ private function autowireMethod(\ReflectionMethod $reflectionMethod, array $argu
279289
if ($value = $this->getAutowiredReference($type)) {
280290
$this->usedTypes[$type] = $this->currentId;
281291
} else {
282-
$failureMessage = $this->createTypeNotFoundMessage($type, 'argument $'.$parameter->name.' of method '.$reflectionMethod->class.'::'.$reflectionMethod->name.'()');
292+
$failureMessage = $this->createTypeNotFoundMessage($type, sprintf('argument $%s of method %s()', $parameter->name, $class !== $this->currentId ? $class.'::'.$method : $method));
283293

284294
if ($parameter->isDefaultValueAvailable()) {
285295
$value = $parameter->getDefaultValue();
@@ -315,14 +325,17 @@ private function autowireOverridenGetters(array $overridenGetters, array $autowi
315325
if (isset($overridenGetters[$lcMethod]) || $reflectionMethod->getNumberOfParameters() || $reflectionMethod->isConstructor()) {
316326
continue;
317327
}
328+
$class = $reflectionMethod->class;
329+
$method = $reflectionMethod->name;
330+
318331
if (!$type = InheritanceProxyHelper::getTypeHint($reflectionMethod, null, true)) {
319332
$type = InheritanceProxyHelper::getTypeHint($reflectionMethod);
320333

321-
throw new RuntimeException(sprintf('Cannot autowire service "%s": getter %s::%s() must%s have its return value be configured explicitly.', $this->currentId, $reflectionMethod->class, $reflectionMethod->name, $type ? '' : ' have a return-type hint or'));
334+
throw new RuntimeException(sprintf('Cannot autowire service "%s": getter %s() must%s have its return value be configured explicitly.', $this->currentId, $class !== $this->currentId ? $class.'::'.$method : $method, $type ? '' : ' have a return-type hint or'));
322335
}
323336

324337
if (!$typeRef = $this->getAutowiredReference($type)) {
325-
$this->container->log($this, $this->createTypeNotFoundMessage($type, 'return value of method '.$reflectionMethod->class.'::'.$reflectionMethod->name.'()'));
338+
$this->container->log($this, $this->createTypeNotFoundMessage($type, sprintf('return value of method %s()', $class !== $this->currentId ? $class.'::'.$method : $method)));
326339
continue;
327340
}
328341

@@ -446,15 +459,14 @@ private function set($type, $id)
446459
*/
447460
private function createAutowiredDefinition(\ReflectionClass $typeHint)
448461
{
449-
if (isset($this->ambiguousServiceTypes[$typeHint->name])) {
450-
$classOrInterface = $typeHint->isInterface() ? 'interface' : 'class';
451-
$matchingServices = implode(', ', $this->ambiguousServiceTypes[$typeHint->name]);
462+
if (isset($this->ambiguousServiceTypes[$type = $typeHint->name])) {
463+
$classOrInterface = class_exists($type) ? 'class' : 'interface';
452464

453-
throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s". Multiple services exist for this %s (%s).', $typeHint->name, $this->currentId, $classOrInterface, $matchingServices));
465+
throw new RuntimeException(sprintf('Cannot autowire service "%s": multiple candidate services exist for %s "%s".%s', $this->currentId, $classOrInterface, $type, $this->createTypeAlternatives($type)));
454466
}
455467

456468
if (!$typeHint->isInstantiable()) {
457-
$this->container->log($this, sprintf('Type "%s" is not instantiable thus cannot be auto-registered for service "%s".', $typeHint->name, $this->currentId));
469+
$this->container->log($this, sprintf('Type "%s" is not instantiable thus cannot be auto-registered for service "%s".', $type, $this->currentId));
458470

459471
return;
460472
}
@@ -463,8 +475,8 @@ private function createAutowiredDefinition(\ReflectionClass $typeHint)
463475
$currentDefinition = $this->currentDefinition;
464476
$definitions = $this->container->getDefinitions();
465477
$currentId = $this->currentId;
466-
$this->currentId = $argumentId = sprintf('autowired.%s', $typeHint->name);
467-
$this->currentDefinition = $argumentDefinition = new Definition($typeHint->name);
478+
$this->currentId = $argumentId = sprintf('autowired.%s', $type);
479+
$this->currentDefinition = $argumentDefinition = new Definition($type);
468480
$argumentDefinition->setPublic(false);
469481
$argumentDefinition->setAutowired(true);
470482

@@ -475,7 +487,7 @@ private function createAutowiredDefinition(\ReflectionClass $typeHint)
475487
$this->container->setDefinition($argumentId, $argumentDefinition);
476488
} catch (RuntimeException $e) {
477489
// revert any changes done to our internal state
478-
unset($this->types[$typeHint->name]);
490+
unset($this->types[$type]);
479491
$this->ambiguousServiceTypes = $ambiguousServiceTypes;
480492
$this->container->setDefinitions($definitions);
481493
$this->container->log($this, $e->getMessage());
@@ -486,19 +498,47 @@ private function createAutowiredDefinition(\ReflectionClass $typeHint)
486498
$this->currentDefinition = $currentDefinition;
487499
}
488500

489-
$this->container->log($this, sprintf('Type "%s" has been auto-registered for service "%s".', $typeHint->name, $this->currentId));
501+
$this->container->log($this, sprintf('Type "%s" has been auto-registered for service "%s".', $type, $this->currentId));
490502

491503
return new Reference($argumentId);
492504
}
493505

494506
private function createTypeNotFoundMessage($type, $label)
495507
{
496508
if (!$classOrInterface = class_exists($type, false) ? 'class' : (interface_exists($type, false) ? 'interface' : null)) {
497-
return sprintf('Cannot autowire %s for service "%s": Class or interface "%s" does not exist.', $label, $this->currentId, $type);
509+
return sprintf('Cannot autowire service "%s": %s has type "%s" but this class does not exist.', $this->currentId, $label, $type);
510+
}
511+
$message = sprintf('no services were found matching the "%s" %s and it cannot be auto-registered for %s.', $type, $classOrInterface, $label);
512+
513+
return sprintf('Cannot autowire service "%s": %s', $this->currentId, $message);
514+
}
515+
516+
private function createTypeAlternatives($type)
517+
{
518+
$message = ' This type-hint could be aliased to ';
519+
520+
if (isset($this->ambiguousServiceTypes[$type])) {
521+
$message .= sprintf('one of these existing services: "%s"', implode('", "', $this->ambiguousServiceTypes[$type]));
522+
} elseif (isset($this->types[$type])) {
523+
$message .= sprintf('the existing "%s" service', $this->types[$type]);
524+
} else {
525+
return;
526+
}
527+
$aliases = array();
528+
529+
foreach (class_parents($type) + class_implements($type) as $parent) {
530+
if ($this->container->has($parent)) {
531+
$aliases[] = $parent;
532+
}
533+
}
534+
535+
if (1 < count($aliases)) {
536+
$message .= sprintf('; or be updated to one of the following: "%s"', implode('", "', $aliases));
537+
} elseif ($aliases) {
538+
$message .= sprintf('; or be updated to "%s"', $aliases[0]);
498539
}
499-
$message = sprintf('No services were found matching the "%s" %s and it cannot be auto-registered', $type, $classOrInterface);
500540

501-
return sprintf('Cannot autowire %s for service "%s": %s.', $label, $this->currentId, $message);
541+
return $message.'.';
502542
}
503543

504544
/**

0 commit comments

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