minor #22326 [DI] Enhance wording of autowiring exceptions (nicolas-grekas)

This PR was merged into the 3.3-dev branch.

Discussion
----------

[DI] Enhance wording of autowiring exceptions

| Q             | A
| ------------- | ---
| Branch?       | 3.3
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | -
| License       | MIT
| Doc PR        | -

> Cannot autowire service "j": argument "$i" of method "Symfony\Component\DependencyInjection\Tests\Compiler\J::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\I" but no such service exists. You should maybe alias this class to the existing "i" service; or type-hint against interface "Symfony\Component\DependencyInjection\Tests\Compiler\IInterface" instead.

Commits
-------

da792b2ff7 [DI] Enhance wording of autowiring exceptions
This commit is contained in:
Fabien Potencier 2017-04-07 09:43:12 -07:00
commit 49ae724e9c
2 changed files with 20 additions and 17 deletions

View File

@ -439,27 +439,30 @@ class AutowirePass extends AbstractRecursivePass
private function createTypeAlternatives($type) private function createTypeAlternatives($type)
{ {
$message = ' This type-hint could be aliased to ';
if (isset($this->ambiguousServiceTypes[$type])) { if (isset($this->ambiguousServiceTypes[$type])) {
$message .= sprintf('one of these existing services: "%s"', implode('", "', $this->ambiguousServiceTypes[$type])); $message = sprintf('one of these existing services: "%s"', implode('", "', $this->ambiguousServiceTypes[$type]));
} elseif (isset($this->types[$type])) { } elseif (isset($this->types[$type])) {
$message .= sprintf('the existing "%s" service', $this->types[$type]); $message = sprintf('the existing "%s" service', $this->types[$type]);
} else { } else {
return; return;
} }
$message = sprintf(' You should maybe alias this %s to %s', class_exists($type, false) ? 'class' : 'interface', $message);
$aliases = array(); $aliases = array();
foreach (class_parents($type) + class_implements($type) as $parent) { foreach (class_parents($type) + class_implements($type) as $parent) {
if ($this->container->has($parent)) { if ($this->container->has($parent) && !$this->container->findDefinition($parent)->isAbstract()) {
$aliases[] = $parent; $aliases[] = $parent;
} }
} }
if (1 < count($aliases)) { if (1 < $len = count($aliases)) {
$message .= sprintf('; or be updated to one of the following: "%s"', implode('", "', $aliases)); $message .= '; or type-hint against one of its parents: ';
for ($i = 0, --$len; $i < $len; ++$i) {
$message .= sprintf('%s "%s", ', class_exists($aliases[$i], false) ? 'class' : 'interface', $aliases[$i]);
}
$message .= sprintf('or %s "%s"', class_exists($aliases[$i], false) ? 'class' : 'interface', $aliases[$i]);
} elseif ($aliases) { } elseif ($aliases) {
$message .= sprintf('; or be updated to "%s"', $aliases[0]); $message .= sprintf('; or type-hint against %s "%s" instead', class_exists($aliases[0], false) ? 'class' : 'interface', $aliases[0]);
} }
return $message.'.'; return $message.'.';

View File

@ -59,7 +59,7 @@ class AutowirePassTest extends TestCase
/** /**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedExceptionMessage Cannot autowire service "c": argument "$a" of method "Symfony\Component\DependencyInjection\Tests\Compiler\C::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\A" but no such service exists. This type-hint could be aliased to the existing "Symfony\Component\DependencyInjection\Tests\Compiler\B" service. * @expectedExceptionMessage Cannot autowire service "c": argument "$a" of method "Symfony\Component\DependencyInjection\Tests\Compiler\C::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\A" but no such service exists. You should maybe alias this class to the existing "Symfony\Component\DependencyInjection\Tests\Compiler\B" service.
*/ */
public function testProcessAutowireParent() public function testProcessAutowireParent()
{ {
@ -78,7 +78,7 @@ class AutowirePassTest extends TestCase
/** /**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedExceptionMessage Cannot autowire service "g": argument "$d" of method "Symfony\Component\DependencyInjection\Tests\Compiler\G::__construct()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\DInterface" but no such service exists. This type-hint could be aliased to the existing "Symfony\Component\DependencyInjection\Tests\Compiler\F" service. * @expectedExceptionMessage Cannot autowire service "g": argument "$d" of method "Symfony\Component\DependencyInjection\Tests\Compiler\G::__construct()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\DInterface" but no such service exists. You should maybe alias this interface to the existing "Symfony\Component\DependencyInjection\Tests\Compiler\F" service.
*/ */
public function testProcessAutowireInterface() public function testProcessAutowireInterface()
{ {
@ -133,7 +133,7 @@ class AutowirePassTest extends TestCase
/** /**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedExceptionMessage Cannot autowire service "a": argument "$collision" of method "Symfony\Component\DependencyInjection\Tests\Compiler\CannotBeAutowired::__construct()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" but no such service exists. This type-hint could be aliased to one of these existing services: "c1", "c2", "c3". * @expectedExceptionMessage Cannot autowire service "a": argument "$collision" of method "Symfony\Component\DependencyInjection\Tests\Compiler\CannotBeAutowired::__construct()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" but no such service exists. You should maybe alias this interface to one of these existing services: "c1", "c2", "c3".
*/ */
public function testTypeCollision() public function testTypeCollision()
{ {
@ -151,7 +151,7 @@ class AutowirePassTest extends TestCase
/** /**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedExceptionMessage Cannot autowire service "a": argument "$k" of method "Symfony\Component\DependencyInjection\Tests\Compiler\NotGuessableArgument::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" but no such service exists. This type-hint could be aliased to one of these existing services: "a1", "a2". * @expectedExceptionMessage Cannot autowire service "a": argument "$k" of method "Symfony\Component\DependencyInjection\Tests\Compiler\NotGuessableArgument::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" but no such service exists. You should maybe alias this class to one of these existing services: "a1", "a2".
*/ */
public function testTypeNotGuessable() public function testTypeNotGuessable()
{ {
@ -168,7 +168,7 @@ class AutowirePassTest extends TestCase
/** /**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedExceptionMessage Cannot autowire service "a": argument "$k" of method "Symfony\Component\DependencyInjection\Tests\Compiler\NotGuessableArgumentForSubclass::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\A" but no such service exists. This type-hint could be aliased to one of these existing services: "a1", "a2". * @expectedExceptionMessage Cannot autowire service "a": argument "$k" of method "Symfony\Component\DependencyInjection\Tests\Compiler\NotGuessableArgumentForSubclass::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\A" but no such service exists. You should maybe alias this class to one of these existing services: "a1", "a2".
*/ */
public function testTypeNotGuessableWithSubclass() public function testTypeNotGuessableWithSubclass()
{ {
@ -334,7 +334,7 @@ class AutowirePassTest extends TestCase
/** /**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedExceptionMessage Cannot autowire service "bar": argument "$foo" of method "Symfony\Component\DependencyInjection\Tests\Compiler\Bar::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" but this service is abstract. This type-hint could be aliased to the existing "foo" service. * @expectedExceptionMessage Cannot autowire service "bar": argument "$foo" of method "Symfony\Component\DependencyInjection\Tests\Compiler\Bar::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" but this service is abstract. You should maybe alias this class to the existing "foo" service.
*/ */
public function testDontUseAbstractServices() public function testDontUseAbstractServices()
{ {
@ -587,7 +587,7 @@ class AutowirePassTest extends TestCase
/** /**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedExceptionMessage Cannot autowire service "setter_injection_collision": argument "$collision" of method "Symfony\Component\DependencyInjection\Tests\Compiler\SetterInjectionCollision::setMultipleInstancesForOneArg()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" but no such service exists. This type-hint could be aliased to one of these existing services: "c1", "c2". * @expectedExceptionMessage Cannot autowire service "setter_injection_collision": argument "$collision" of method "Symfony\Component\DependencyInjection\Tests\Compiler\SetterInjectionCollision::setMultipleInstancesForOneArg()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" but no such service exists. You should maybe alias this interface to one of these existing services: "c1", "c2".
*/ */
public function testSetterInjectionCollisionThrowsException() public function testSetterInjectionCollisionThrowsException()
{ {
@ -604,7 +604,7 @@ class AutowirePassTest extends TestCase
/** /**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedExceptionMessage Cannot autowire service "bar": argument "$foo" of method "Symfony\Component\DependencyInjection\Tests\Compiler\Bar::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" but no such service exists. This type-hint could be aliased to the existing "foo" service. * @expectedExceptionMessage Cannot autowire service "bar": argument "$foo" of method "Symfony\Component\DependencyInjection\Tests\Compiler\Bar::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" but no such service exists. You should maybe alias this class to the existing "foo" service.
*/ */
public function testProcessDoesNotTriggerDeprecations() public function testProcessDoesNotTriggerDeprecations()
{ {
@ -688,7 +688,7 @@ class AutowirePassTest extends TestCase
/** /**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedExceptionMessage Cannot autowire service "j": argument "$i" of method "Symfony\Component\DependencyInjection\Tests\Compiler\J::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\I" but no such service exists. This type-hint could be aliased to the existing "i" service; or be updated to "Symfony\Component\DependencyInjection\Tests\Compiler\IInterface". * @expectedExceptionMessage Cannot autowire service "j": argument "$i" of method "Symfony\Component\DependencyInjection\Tests\Compiler\J::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\I" but no such service exists. You should maybe alias this class to the existing "i" service; or type-hint against interface "Symfony\Component\DependencyInjection\Tests\Compiler\IInterface" instead.
*/ */
public function testByIdAlternative() public function testByIdAlternative()
{ {