bug #21665 [DependencyInjection] Fix autowiring collisions detection (nicolas-grekas, GuilhemN)
This PR was merged into the 2.8 branch. Discussion ---------- [DependencyInjection] Fix autowiring collisions detection | Q | A | ------------- | --- | Branch? | 2.8 | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | Fixes https://github.com/symfony/symfony/pull/21658 by implementing the second proposal of https://github.com/symfony/symfony/pull/21658#issuecomment-280858452: > Another idea: store the types used previously and check that new services registered don't implement them. Commits -------bb70472dce
[DependencyInjection] Fix autowiring collisions detection6f578ee514
[DI] Bug in autowiring collisions detection
This commit is contained in:
commit
3cfd04bd18
@ -28,6 +28,7 @@ class AutowirePass implements CompilerPassInterface
|
|||||||
private $definedTypes = array();
|
private $definedTypes = array();
|
||||||
private $types;
|
private $types;
|
||||||
private $notGuessableTypes = array();
|
private $notGuessableTypes = array();
|
||||||
|
private $usedTypes = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
@ -44,6 +45,15 @@ class AutowirePass implements CompilerPassInterface
|
|||||||
$this->completeDefinition($id, $definition);
|
$this->completeDefinition($id, $definition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach ($this->usedTypes as $type => $id) {
|
||||||
|
if (isset($this->usedTypes[$type]) && isset($this->notGuessableTypes[$type])) {
|
||||||
|
$classOrInterface = class_exists($type) ? 'class' : 'interface';
|
||||||
|
$matchingServices = implode(', ', $this->types[$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));
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
}
|
}
|
||||||
@ -56,6 +66,7 @@ class AutowirePass implements CompilerPassInterface
|
|||||||
$this->definedTypes = array();
|
$this->definedTypes = array();
|
||||||
$this->types = null;
|
$this->types = null;
|
||||||
$this->notGuessableTypes = array();
|
$this->notGuessableTypes = array();
|
||||||
|
$this->usedTypes = array();
|
||||||
|
|
||||||
if (isset($e)) {
|
if (isset($e)) {
|
||||||
throw $e;
|
throw $e;
|
||||||
@ -109,9 +120,11 @@ class AutowirePass implements CompilerPassInterface
|
|||||||
|
|
||||||
if (isset($this->types[$typeHint->name]) && !isset($this->notGuessableTypes[$typeHint->name])) {
|
if (isset($this->types[$typeHint->name]) && !isset($this->notGuessableTypes[$typeHint->name])) {
|
||||||
$value = new Reference($this->types[$typeHint->name]);
|
$value = new Reference($this->types[$typeHint->name]);
|
||||||
|
$this->usedTypes[$typeHint->name] = $id;
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
$value = $this->createAutowiredDefinition($typeHint, $id);
|
$value = $this->createAutowiredDefinition($typeHint, $id);
|
||||||
|
$this->usedTypes[$typeHint->name] = $id;
|
||||||
} catch (RuntimeException $e) {
|
} catch (RuntimeException $e) {
|
||||||
if ($parameter->allowsNull()) {
|
if ($parameter->allowsNull()) {
|
||||||
$value = null;
|
$value = null;
|
||||||
|
@ -459,6 +459,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
|
||||||
@ -540,6 +565,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