bug #18766 Make failed autowiring error messages more explicit (lemoinem)

This PR was merged into the 3.1-dev branch.

Discussion
----------

Make failed autowiring error messages more explicit

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no (better DX integration)
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #18658
| License       | MIT
| Doc PR        | N/A

@nicolas-grekas This is a port from #18691 (which was for **2.8**).
It looks like the original PR has been already mostly implemented in **master** by @weaverryan (in #17877).

IMO, this PR is still improving two use cases:

  * In case a class cannot be autowired because no service can be found AND a service cannot be registered automatically, the error message now mentions both conditions (instead of simply saying no service has been found)
  * In case a class with no service attached to it can be automatically instantiated but cannot be autowired because of further problems, an exception mentioning this is now thrown instead of the lower level exception, making the situation easier to debug. (The lower level exception is still available through `getPrevious()`)

Hence, I still think this PR provides useful additional DX features and is worth to be merged.

Commits
-------

6894e03 Make failed autowiring error messages more explicit
This commit is contained in:
Fabien Potencier 2016-05-13 12:58:08 -05:00
commit 219b050d30
2 changed files with 10 additions and 3 deletions

View File

@ -271,7 +271,7 @@ class AutowirePass implements CompilerPassInterface
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));
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);
@ -280,7 +280,14 @@ class AutowirePass implements CompilerPassInterface
$argumentDefinition->setPublic(false);
$this->populateAvailableType($argumentId, $argumentDefinition);
$this->completeDefinition($argumentId, $argumentDefinition);
try {
$this->completeDefinition($argumentId, $argumentDefinition);
} catch (\RuntimeException $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);
}

View File

@ -155,7 +155,7 @@ class AutowirePassTest extends \PHPUnit_Framework_TestCase
/**
* @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.
* @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()
{