Merge branch '3.2'
* 3.2: [DependencyInjection] Fix using autowiring types when there are more than 2 services [DependencyInjection] Fix autowiring collisions detection [DI] Bug in autowiring collisions detection
This commit is contained in:
commit
a399e7594b
@ -37,6 +37,7 @@ class AutowirePass extends AbstractRecursivePass
|
|||||||
private $definedTypes = array();
|
private $definedTypes = array();
|
||||||
private $types;
|
private $types;
|
||||||
private $ambiguousServiceTypes = array();
|
private $ambiguousServiceTypes = array();
|
||||||
|
private $usedTypes = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
@ -45,11 +46,27 @@ class AutowirePass extends AbstractRecursivePass
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
parent::process($container);
|
parent::process($container);
|
||||||
|
|
||||||
|
foreach ($this->usedTypes as $type => $id) {
|
||||||
|
if (!isset($this->usedTypes[$type]) || !isset($this->ambiguousServiceTypes[$type])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($container->has($type) && !$container->findDefinition($type)->isAbstract()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$classOrInterface = class_exists($type) ? 'class' : 'interface';
|
||||||
|
$matchingServices = implode(', ', $this->ambiguousServiceTypes[$type]);
|
||||||
|
|
||||||
|
throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s". Multiple services exist for this %s (%s).', $type, $id, $classOrInterface, $matchingServices));
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
// Free memory
|
// Free memory
|
||||||
$this->definedTypes = array();
|
$this->definedTypes = array();
|
||||||
$this->types = null;
|
$this->types = null;
|
||||||
$this->ambiguousServiceTypes = array();
|
$this->ambiguousServiceTypes = array();
|
||||||
|
$this->usedTypes = array();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -271,10 +288,12 @@ class AutowirePass extends AbstractRecursivePass
|
|||||||
if (isset($this->types[$typeName])) {
|
if (isset($this->types[$typeName])) {
|
||||||
$value = new Reference($this->types[$typeName]);
|
$value = new Reference($this->types[$typeName]);
|
||||||
$didAutowire = true;
|
$didAutowire = true;
|
||||||
|
$this->usedTypes[$typeName] = $this->currentId;
|
||||||
} elseif ($typeHint = $this->container->getReflectionClass($typeName, true)) {
|
} elseif ($typeHint = $this->container->getReflectionClass($typeName, true)) {
|
||||||
try {
|
try {
|
||||||
$value = $this->createAutowiredDefinition($typeHint);
|
$value = $this->createAutowiredDefinition($typeHint);
|
||||||
$didAutowire = true;
|
$didAutowire = true;
|
||||||
|
$this->usedTypes[$typeName] = $this->currentId;
|
||||||
} catch (RuntimeException $e) {
|
} catch (RuntimeException $e) {
|
||||||
if ($parameter->allowsNull()) {
|
if ($parameter->allowsNull()) {
|
||||||
$value = null;
|
$value = null;
|
||||||
@ -354,6 +373,10 @@ class AutowirePass extends AbstractRecursivePass
|
|||||||
try {
|
try {
|
||||||
$value = $this->createAutowiredDefinition($returnType);
|
$value = $this->createAutowiredDefinition($returnType);
|
||||||
} catch (RuntimeException $e) {
|
} catch (RuntimeException $e) {
|
||||||
|
if (1 === $e->getCode()) {
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -361,6 +384,7 @@ class AutowirePass extends AbstractRecursivePass
|
|||||||
}
|
}
|
||||||
|
|
||||||
$overridenGetters[$lcMethod] = $value;
|
$overridenGetters[$lcMethod] = $value;
|
||||||
|
$this->usedTypes[$typeName] = $this->currentId;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $overridenGetters;
|
return $overridenGetters;
|
||||||
@ -394,6 +418,7 @@ class AutowirePass extends AbstractRecursivePass
|
|||||||
foreach ($definition->getAutowiringTypes(false) as $type) {
|
foreach ($definition->getAutowiringTypes(false) as $type) {
|
||||||
$this->definedTypes[$type] = true;
|
$this->definedTypes[$type] = true;
|
||||||
$this->types[$type] = $id;
|
$this->types[$type] = $id;
|
||||||
|
unset($this->ambiguousServiceTypes[$type]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$reflectionClass = $this->container->getReflectionClass($definition->getClass(), true)) {
|
if (!$reflectionClass = $this->container->getReflectionClass($definition->getClass(), true)) {
|
||||||
|
@ -192,6 +192,7 @@ class AutowirePassTest extends \PHPUnit_Framework_TestCase
|
|||||||
$container = new ContainerBuilder();
|
$container = new ContainerBuilder();
|
||||||
|
|
||||||
$container->register('a1', __NAMESPACE__.'\Foo');
|
$container->register('a1', __NAMESPACE__.'\Foo');
|
||||||
|
$container->register('a2', __NAMESPACE__.'\Foo');
|
||||||
$container->register(Foo::class, Foo::class);
|
$container->register(Foo::class, Foo::class);
|
||||||
$aDefinition = $container->register('a', __NAMESPACE__.'\NotGuessableArgument');
|
$aDefinition = $container->register('a', __NAMESPACE__.'\NotGuessableArgument');
|
||||||
$aDefinition->setAutowired(true);
|
$aDefinition->setAutowired(true);
|
||||||
@ -542,6 +543,26 @@ class AutowirePassTest extends \PHPUnit_Framework_TestCase
|
|||||||
), $overridenGetters);
|
), $overridenGetters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @requires PHP 7.1
|
||||||
|
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
|
||||||
|
* @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" for the service "getter_overriding". Multiple services exist for this class (a1, a2).
|
||||||
|
*/
|
||||||
|
public function testGetterOverridingWithAmbiguousServices()
|
||||||
|
{
|
||||||
|
$container = new ContainerBuilder();
|
||||||
|
$container->register('a1', Foo::class);
|
||||||
|
$container->register('a2', Foo::class);
|
||||||
|
|
||||||
|
$container
|
||||||
|
->register('getter_overriding', GetterOverriding::class)
|
||||||
|
->setAutowiredCalls(array('getFoo'))
|
||||||
|
;
|
||||||
|
|
||||||
|
$pass = new AutowirePass();
|
||||||
|
$pass->process($container);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider getCreateResourceTests
|
* @dataProvider getCreateResourceTests
|
||||||
* @group legacy
|
* @group legacy
|
||||||
@ -637,6 +658,31 @@ class AutowirePassTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
$this->assertEquals(array(new Reference('a'), '', new Reference('lille')), $container->getDefinition('foo')->getArguments());
|
$this->assertEquals(array(new Reference('a'), '', new Reference('lille')), $container->getDefinition('foo')->getArguments());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provideAutodiscoveredAutowiringOrder
|
||||||
|
*
|
||||||
|
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
|
||||||
|
* @expectedExceptionMEssage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" for the service "a". Multiple services exist for this interface (autowired.Symfony\Component\DependencyInjection\Tests\Compiler\CollisionA, autowired.Symfony\Component\DependencyInjection\Tests\Compiler\CollisionB).
|
||||||
|
*/
|
||||||
|
public function testAutodiscoveredAutowiringOrder($class)
|
||||||
|
{
|
||||||
|
$container = new ContainerBuilder();
|
||||||
|
|
||||||
|
$container->register('a', __NAMESPACE__.'\\'.$class)
|
||||||
|
->setAutowired(true);
|
||||||
|
|
||||||
|
$pass = new AutowirePass();
|
||||||
|
$pass->process($container);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provideAutodiscoveredAutowiringOrder()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
array('CannotBeAutowiredForwardOrder'),
|
||||||
|
array('CannotBeAutowiredReverseOrder'),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Foo
|
class Foo
|
||||||
@ -718,6 +764,20 @@ class CannotBeAutowired
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CannotBeAutowiredForwardOrder
|
||||||
|
{
|
||||||
|
public function __construct(CollisionA $a, CollisionInterface $b, CollisionB $c)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CannotBeAutowiredReverseOrder
|
||||||
|
{
|
||||||
|
public function __construct(CollisionA $a, CollisionB $c, CollisionInterface $b)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class Lille
|
class Lille
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user