Fixing a bug where an autowiring exception was thrown even when that service was removed

The specific report was for a service with a private constructor. This also clarifies
that the AutowirePass throws AutowiringFailedException for all situations. And a bug
was fixed in the constructor of AutowiringFailedException
This commit is contained in:
Ryan Weaver 2017-05-31 09:45:25 -04:00
parent 5473373473
commit 2d3e44e11e
3 changed files with 44 additions and 17 deletions

View File

@ -133,7 +133,13 @@ class AutowirePass extends AbstractRecursivePass
$autowiredMethods = $this->getMethodsToAutowire($reflectionClass);
$methodCalls = $value->getMethodCalls();
if ($constructor = $this->getConstructor($value, false)) {
try {
$constructor = $this->getConstructor($value, false);
} catch (RuntimeException $e) {
throw new AutowiringFailedException($this->currentId, $e->getMessage(), 0, $e);
}
if ($constructor) {
array_unshift($methodCalls, array($constructor, $value->getArguments()));
}
@ -242,7 +248,7 @@ class AutowirePass extends AbstractRecursivePass
*
* @return array The autowired arguments
*
* @throws RuntimeException
* @throws AutowiringFailedException
*/
private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, array $arguments)
{

View File

@ -18,7 +18,7 @@ class AutowiringFailedException extends RuntimeException
{
private $serviceId;
public function __construct($serviceId, $message = '', $code = 0, Exception $previous = null)
public function __construct($serviceId, $message = '', $code = 0, \Exception $previous = null)
{
$this->serviceId = $serviceId;

View File

@ -151,7 +151,21 @@ class AutowirePassTest extends TestCase
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
* @expectedExceptionMessage Unable to resolve service "private_service": constructor of class "Symfony\Component\DependencyInjection\Tests\Compiler\PrivateConstructor" must be public.
*/
public function testPrivateConstructorThrowsAutowireException()
{
$container = new ContainerBuilder();
$container->autowire('private_service', __NAMESPACE__.'\PrivateConstructor');
$pass = new AutowirePass(true);
$pass->process($container);
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
* @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()
@ -169,7 +183,7 @@ class AutowirePassTest extends TestCase
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
* @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()
@ -186,7 +200,7 @@ class AutowirePassTest extends TestCase
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
* @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()
@ -203,7 +217,7 @@ class AutowirePassTest extends TestCase
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
* @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.
*/
public function testTypeNotGuessableNoServicesFound()
@ -322,7 +336,7 @@ class AutowirePassTest extends TestCase
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
* @expectedExceptionMessage Cannot autowire service "a": argument "$r" of method "Symfony\Component\DependencyInjection\Tests\Compiler\BadTypeHintedArgument::__construct()" has type "Symfony\Component\DependencyInjection\Tests\Compiler\NotARealClass" but this class does not exist.
*/
public function testClassNotFoundThrowsException()
@ -337,7 +351,7 @@ class AutowirePassTest extends TestCase
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
* @expectedExceptionMessage Cannot autowire service "a": argument "$r" of method "Symfony\Component\DependencyInjection\Tests\Compiler\BadParentTypeHintedArgument::__construct()" has type "Symfony\Component\DependencyInjection\Tests\Compiler\OptionalServiceClass" but this class does not exist.
*/
public function testParentClassNotFoundThrowsException()
@ -354,7 +368,7 @@ class AutowirePassTest extends TestCase
/**
* @group legacy
* @expectedDeprecation Autowiring services based on the types they implement is deprecated since Symfony 3.3 and won't be supported in version 4.0. You should rename (or alias) the "foo" service to "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" instead.
* @expectedExceptionInSymfony4 \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedExceptionInSymfony4 \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
* @expectedExceptionMessageInSymfony4 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()
@ -399,7 +413,7 @@ class AutowirePassTest extends TestCase
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
* @expectedExceptionMessage Cannot autowire service "arg_no_type_hint": argument "$foo" of method "Symfony\Component\DependencyInjection\Tests\Compiler\MultipleArguments::__construct()" must have a type-hint or be given a value explicitly.
*/
public function testScalarArgsCannotBeAutowired()
@ -607,7 +621,7 @@ class AutowirePassTest extends TestCase
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
* @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()
@ -626,7 +640,7 @@ class AutowirePassTest extends TestCase
/**
* @group legacy
* @expectedDeprecation Autowiring services based on the types they implement is deprecated since Symfony 3.3 and won't be supported in version 4.0. You should rename (or alias) the "foo" service to "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" instead.
* @expectedExceptionInSymfony4 \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedExceptionInSymfony4 \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
* @expectedExceptionMessageInSymfony4 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()
@ -677,7 +691,7 @@ class AutowirePassTest extends TestCase
/**
* @dataProvider provideNotWireableCalls
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
*/
public function testNotWireableCalls($method, $expectedMsg)
{
@ -717,7 +731,7 @@ class AutowirePassTest extends TestCase
/**
* @group legacy
* @expectedDeprecation Autowiring services based on the types they implement is deprecated since Symfony 3.3 and won't be supported in version 4.0. You should rename (or alias) the "i" service to "Symfony\Component\DependencyInjection\Tests\Compiler\I" instead.
* @expectedExceptionInSymfony4 \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedExceptionInSymfony4 \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
* @expectedExceptionMessageInSymfony4 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. Try changing the type-hint to "Symfony\Component\DependencyInjection\Tests\Compiler\IInterface" instead.
*/
public function testByIdAlternative()
@ -734,7 +748,7 @@ class AutowirePassTest extends TestCase
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
* @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. Try changing the type-hint to "Symfony\Component\DependencyInjection\Tests\Compiler\IInterface" instead.
*/
public function testExceptionWhenAliasExists()
@ -754,7 +768,7 @@ class AutowirePassTest extends TestCase
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
* @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 one of these existing services: "i", "i2".
*/
public function testExceptionWhenAliasDoesNotExist()
@ -1091,3 +1105,10 @@ class NotWireable
{
}
}
class PrivateConstructor
{
private function __construct()
{
}
}