Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f5d2937

Browse files
[DI] Add hints to exceptions thrown by AutowiringPass
1 parent 2ad5923 commit f5d2937

File tree

2 files changed

+105
-38
lines changed

2 files changed

+105
-38
lines changed

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

Lines 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)