Skip to content

Commit

Permalink
minor #18780 [DX][DependencyInjection] Make Autowiring exceptions mor…
Browse files Browse the repository at this point in the history
…e future friendly (lemoinem)

This PR was merged into the 2.8 branch.

Discussion
----------

[DX][DependencyInjection] Make Autowiring exceptions more future friendly

| Q             | A
| ------------- | ---
| Branch?       | 2.8, 3.0
| Bug fix?      | no (forward compatibility)
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | N/A
| License       | MIT
| Doc PR        | N/A

This is a follow-up on #18766 (3.1, master) and #18691 (2.8, 3.0).

This PR changes the exception messages to the ones introduced in #18766 and #17877. I also unified the tests so they are exactly the same.

This way the error messages will be the same in 2.8 onward.

Commits
-------

834f550 [DX][DI] Make Autowiring exceptions more future friendly
  • Loading branch information
nicolas-grekas committed May 19, 2016
2 parents bcdf568 + 834f550 commit 39a18cd
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 23 deletions.
Expand Up @@ -225,13 +225,16 @@ private function set($type, $id)
private function createAutowiredDefinition(\ReflectionClass $typeHint, $id)
{
if (isset($this->notGuessableTypes[$typeHint->name])) {
throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s". Several services implementing this type have been declared: "%s".', $typeHint->name, $id, implode('", "', $this->types[$typeHint->name])));
}
$classOrInterface = $typeHint->isInterface() ? 'interface' : 'class';
$matchingServices = implode(', ', $this->types[$typeHint->name]);

throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s". Multiple services exist for this %s (%s).', $typeHint->name, $id, $classOrInterface, $matchingServices));

$noAvailableDefinitionMessage = sprintf('Unable to autowire argument of type "%s" for the service "%s". This type cannot be instantiated automatically and no service implementing this type is declared.', $typeHint->name, $id);
}

if (!$typeHint->isInstantiable()) {
throw new RuntimeException($noAvailableDefinitionMessage);
$classOrInterface = $typeHint->isInterface() ? 'interface' : 'class';
throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s". No services were found matching this %s and it cannot be auto-registered.', $typeHint->name, $id, $classOrInterface));
}

$argumentId = sprintf('autowired.%s', $typeHint->name);
Expand All @@ -244,7 +247,9 @@ private function createAutowiredDefinition(\ReflectionClass $typeHint, $id)
try {
$this->completeDefinition($argumentId, $argumentDefinition);
} catch (RuntimeException $e) {
throw new RuntimeException($noAvailableDefinitionMessage, 0, $e);
$classOrInterface = $typeHint->isInterface() ? 'interface' : 'class';
$message = sprintf('Unable to autowire argument of type "%s" for the service "%s". No services were found matching this %s and it cannot be auto-registered.', $typeHint->name, $id, $classOrInterface);
throw new RuntimeException($message, 0, $e);
}

return new Reference($argumentId);
Expand Down
Expand Up @@ -103,14 +103,15 @@ public function testCompleteExistingDefinitionWithNotDefinedArguments()

/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" for the service "a". Several services implementing this type have been declared: "c1", "c2".
* @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" for the service "a". Multiple services exist for this interface (c1, c2, c3).
*/
public function testTypeCollision()
{
$container = new ContainerBuilder();

$container->register('c1', __NAMESPACE__.'\CollisionA');
$container->register('c2', __NAMESPACE__.'\CollisionB');
$container->register('c3', __NAMESPACE__.'\CollisionB');
$aDefinition = $container->register('a', __NAMESPACE__.'\CannotBeAutowired');
$aDefinition->setAutowired(true);

Expand All @@ -120,7 +121,7 @@ public function testTypeCollision()

/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" for the service "a". Several services implementing this type have been declared: "a1", "a2".
* @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" for the service "a". Multiple services exist for this class (a1, a2).
*/
public function testTypeNotGuessable()
{
Expand All @@ -137,7 +138,7 @@ public function testTypeNotGuessable()

/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\A" for the service "a". Several services implementing this type have been declared: "a1", "a2".
* @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\A" for the service "a". Multiple services exist for this class (a1, a2).
*/
public function testTypeNotGuessableWithSubclass()
{
Expand All @@ -152,6 +153,21 @@ public function testTypeNotGuessableWithSubclass()
$pass->process($container);
}

/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" for the service "a". No services were found matching this interface and it cannot be auto-registered.
*/
public function testTypeNotGuessableNoServicesFound()
{
$container = new ContainerBuilder();

$aDefinition = $container->register('a', __NAMESPACE__.'\CannotBeAutowired');
$aDefinition->setAutowired(true);

$pass = new AutowirePass();
$pass->process($container);
}

public function testTypeNotGuessableWithTypeSet()
{
$container = new ContainerBuilder();
Expand Down Expand Up @@ -207,21 +223,6 @@ public function testCreateDefinition()
$this->assertEquals(__NAMESPACE__.'\Lille', $lilleDefinition->getClass());
}

/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" for the service "a". This type cannot be instantiated automatically and no service implementing this type is declared.
*/
public function testCreateNonInstanciable()
{
$container = new ContainerBuilder();

$aDefinition = $container->register('a', __NAMESPACE__.'\CannotBeAutowired');
$aDefinition->setAutowired(true);

$pass = new AutowirePass();
$pass->process($container);
}

public function testResolveParameter()
{
$container = new ContainerBuilder();
Expand Down

0 comments on commit 39a18cd

Please sign in to comment.