Skip to content

Commit

Permalink
feature #17877 [DependencyInjection] Improving autowiring error messa…
Browse files Browse the repository at this point in the history
…ges (weaverryan)

This PR was merged into the 3.1-dev branch.

Discussion
----------

[DependencyInjection] Improving autowiring error messages

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

This does not change any behavior, but changes error messages to be more descriptive.

**Before**
> Unable to autowire argument of type "Doctrine\ORM\EntityManager"
> for the service "my_cool_service".

**After**
> Unable to autowire argument of type "Doctrine\ORM\EntityManager"
> for the service "my_cool_service". Multiple services exist for this class
> (doctrine.orm.default_entity_manager, doctrine_orm.other_entity_manager).

Commits
-------

6fe97f9 [DependencyInjection] Improving autowiring error messages to say *why* something cannot be autowired
  • Loading branch information
fabpot committed Feb 22, 2016
2 parents 0813705 + 6fe97f9 commit 66a64ae
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 9 deletions.
Expand Up @@ -27,7 +27,7 @@ class AutowirePass implements CompilerPassInterface
private $reflectionClasses = array();
private $definedTypes = array();
private $types;
private $notGuessableTypes = array();
private $ambiguousServiceTypes = array();

/**
* {@inheritdoc}
Expand All @@ -46,7 +46,7 @@ public function process(ContainerBuilder $container)
$this->reflectionClasses = array();
$this->definedTypes = array();
$this->types = null;
$this->notGuessableTypes = array();
$this->ambiguousServiceTypes = array();
}

/**
Expand Down Expand Up @@ -197,17 +197,25 @@ private function extractAncestors($id, \ReflectionClass $reflectionClass)
*/
private function set($type, $id)
{
if (isset($this->definedTypes[$type]) || isset($this->notGuessableTypes[$type])) {
if (isset($this->definedTypes[$type])) {
return;
}

// check to make sure the type doesn't match multiple services
if (isset($this->types[$type])) {
if ($this->types[$type] === $id) {
return;
}

// keep an array of all services matching this type
if (!isset($this->ambiguousServiceTypes[$type])) {
$this->ambiguousServiceTypes[$type] = array(
$this->types[$type],
);
}
$this->ambiguousServiceTypes[$type][] = $id;

unset($this->types[$type]);
$this->notGuessableTypes[$type] = true;

return;
}
Expand All @@ -227,8 +235,16 @@ private function set($type, $id)
*/
private function createAutowiredDefinition(\ReflectionClass $typeHint, $id)
{
if (isset($this->notGuessableTypes[$typeHint->name]) || !$typeHint->isInstantiable()) {
throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s".', $typeHint->name, $id));
if (isset($this->ambiguousServiceTypes[$typeHint->name])) {
$classOrInterface = $typeHint->isInterface() ? 'interface' : 'class';
$matchingServices = implode(', ', $this->ambiguousServiceTypes[$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));
}

if (!$typeHint->isInstantiable()) {
$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.', $typeHint->name, $id, $classOrInterface));
}

$argumentId = sprintf('autowired.%s', $typeHint->name);
Expand Down
Expand Up @@ -102,7 +102,7 @@ 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".
* @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).
*/
public function testTypeCollision()
{
Expand All @@ -119,7 +119,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".
* @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 @@ -136,7 +136,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".
* @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 @@ -151,6 +151,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.
*/
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

0 comments on commit 66a64ae

Please sign in to comment.