[DI] Detect circular references with ChildDefinition parent
This commit is contained in:
parent
7a19350fa8
commit
2a59c8e3e6
@ -15,6 +15,7 @@ use Symfony\Component\DependencyInjection\ChildDefinition;
|
|||||||
use Symfony\Component\DependencyInjection\Definition;
|
use Symfony\Component\DependencyInjection\Definition;
|
||||||
use Symfony\Component\DependencyInjection\Exception\ExceptionInterface;
|
use Symfony\Component\DependencyInjection\Exception\ExceptionInterface;
|
||||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||||
|
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This replaces all ChildDefinition instances with their equivalent fully
|
* This replaces all ChildDefinition instances with their equivalent fully
|
||||||
@ -25,6 +26,8 @@ use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
|||||||
*/
|
*/
|
||||||
class ResolveChildDefinitionsPass extends AbstractRecursivePass
|
class ResolveChildDefinitionsPass extends AbstractRecursivePass
|
||||||
{
|
{
|
||||||
|
private $currentPath;
|
||||||
|
|
||||||
protected function processValue($value, $isRoot = false)
|
protected function processValue($value, $isRoot = false)
|
||||||
{
|
{
|
||||||
if (!$value instanceof Definition) {
|
if (!$value instanceof Definition) {
|
||||||
@ -36,6 +39,7 @@ class ResolveChildDefinitionsPass extends AbstractRecursivePass
|
|||||||
$value = $this->container->getDefinition($this->currentId);
|
$value = $this->container->getDefinition($this->currentId);
|
||||||
}
|
}
|
||||||
if ($value instanceof ChildDefinition) {
|
if ($value instanceof ChildDefinition) {
|
||||||
|
$this->currentPath = array();
|
||||||
$value = $this->resolveDefinition($value);
|
$value = $this->resolveDefinition($value);
|
||||||
if ($isRoot) {
|
if ($isRoot) {
|
||||||
$this->container->setDefinition($this->currentId, $value);
|
$this->container->setDefinition($this->currentId, $value);
|
||||||
@ -56,6 +60,8 @@ class ResolveChildDefinitionsPass extends AbstractRecursivePass
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
return $this->doResolveDefinition($definition);
|
return $this->doResolveDefinition($definition);
|
||||||
|
} catch (ServiceCircularReferenceException $e) {
|
||||||
|
throw $e;
|
||||||
} catch (ExceptionInterface $e) {
|
} catch (ExceptionInterface $e) {
|
||||||
$r = new \ReflectionProperty($e, 'message');
|
$r = new \ReflectionProperty($e, 'message');
|
||||||
$r->setAccessible(true);
|
$r->setAccessible(true);
|
||||||
@ -71,6 +77,13 @@ class ResolveChildDefinitionsPass extends AbstractRecursivePass
|
|||||||
throw new RuntimeException(sprintf('Parent definition "%s" does not exist.', $parent));
|
throw new RuntimeException(sprintf('Parent definition "%s" does not exist.', $parent));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$searchKey = array_search($parent, $this->currentPath);
|
||||||
|
$this->currentPath[] = $parent;
|
||||||
|
|
||||||
|
if (false !== $searchKey) {
|
||||||
|
throw new ServiceCircularReferenceException($parent, \array_slice($this->currentPath, $searchKey));
|
||||||
|
}
|
||||||
|
|
||||||
$parentDef = $this->container->findDefinition($parent);
|
$parentDef = $this->container->findDefinition($parent);
|
||||||
if ($parentDef instanceof ChildDefinition) {
|
if ($parentDef instanceof ChildDefinition) {
|
||||||
$id = $this->currentId;
|
$id = $this->currentId;
|
||||||
|
@ -431,4 +431,21 @@ class ResolveChildDefinitionsPassTest extends TestCase
|
|||||||
$pass = new ResolveChildDefinitionsPass();
|
$pass = new ResolveChildDefinitionsPass();
|
||||||
$pass->process($container);
|
$pass->process($container);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException
|
||||||
|
* @expectedExceptionMessageRegExp /^Circular reference detected for service "c", path: "c -> b -> a -> c"./
|
||||||
|
*/
|
||||||
|
public function testProcessDetectsChildDefinitionIndirectCircularReference()
|
||||||
|
{
|
||||||
|
$container = new ContainerBuilder();
|
||||||
|
|
||||||
|
$container->register('a');
|
||||||
|
|
||||||
|
$container->setDefinition('b', new ChildDefinition('a'));
|
||||||
|
$container->setDefinition('c', new ChildDefinition('b'));
|
||||||
|
$container->setDefinition('a', new ChildDefinition('c'));
|
||||||
|
|
||||||
|
$this->process($container);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user