Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c4c2981

Browse files
bug #28480 [DI] Detect circular references with ChildDefinition parent (Seb33300)
This PR was submitted for the master branch but it was squashed and merged into the 3.4 branch instead (closes #28480). Discussion ---------- [DI] Detect circular references with ChildDefinition parent | Q | A | ------------- | --- | Branch? | 3.4 (be careful when merging) | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #28312 | License | MIT | Doc PR | I will provide a test case if the fix looks good for you :) Commits ------- 2a59c8e [DI] Detect circular references with ChildDefinition parent
2 parents 7a19350 + 2a59c8e commit c4c2981

File tree

2 files changed

+30
-0
lines changed

2 files changed

+30
-0
lines changed

src/Symfony/Component/DependencyInjection/Compiler/ResolveChildDefinitionsPass.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\Component\DependencyInjection\Definition;
1616
use Symfony\Component\DependencyInjection\Exception\ExceptionInterface;
1717
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
18+
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
1819

1920
/**
2021
* This replaces all ChildDefinition instances with their equivalent fully
@@ -25,6 +26,8 @@
2526
*/
2627
class ResolveChildDefinitionsPass extends AbstractRecursivePass
2728
{
29+
private $currentPath;
30+
2831
protected function processValue($value, $isRoot = false)
2932
{
3033
if (!$value instanceof Definition) {
@@ -36,6 +39,7 @@ protected function processValue($value, $isRoot = false)
3639
$value = $this->container->getDefinition($this->currentId);
3740
}
3841
if ($value instanceof ChildDefinition) {
42+
$this->currentPath = array();
3943
$value = $this->resolveDefinition($value);
4044
if ($isRoot) {
4145
$this->container->setDefinition($this->currentId, $value);
@@ -56,6 +60,8 @@ private function resolveDefinition(ChildDefinition $definition)
5660
{
5761
try {
5862
return $this->doResolveDefinition($definition);
63+
} catch (ServiceCircularReferenceException $e) {
64+
throw $e;
5965
} catch (ExceptionInterface $e) {
6066
$r = new \ReflectionProperty($e, 'message');
6167
$r->setAccessible(true);
@@ -71,6 +77,13 @@ private function doResolveDefinition(ChildDefinition $definition)
7177
throw new RuntimeException(sprintf('Parent definition "%s" does not exist.', $parent));
7278
}
7379

80+
$searchKey = array_search($parent, $this->currentPath);
81+
$this->currentPath[] = $parent;
82+
83+
if (false !== $searchKey) {
84+
throw new ServiceCircularReferenceException($parent, \array_slice($this->currentPath, $searchKey));
85+
}
86+
7487
$parentDef = $this->container->findDefinition($parent);
7588
if ($parentDef instanceof ChildDefinition) {
7689
$id = $this->currentId;

src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveChildDefinitionsPassTest.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,4 +431,21 @@ protected function process(ContainerBuilder $container)
431431
$pass = new ResolveChildDefinitionsPass();
432432
$pass->process($container);
433433
}
434+
435+
/**
436+
* @expectedException \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException
437+
* @expectedExceptionMessageRegExp /^Circular reference detected for service "c", path: "c -> b -> a -> c"./
438+
*/
439+
public function testProcessDetectsChildDefinitionIndirectCircularReference()
440+
{
441+
$container = new ContainerBuilder();
442+
443+
$container->register('a');
444+
445+
$container->setDefinition('b', new ChildDefinition('a'));
446+
$container->setDefinition('c', new ChildDefinition('b'));
447+
$container->setDefinition('a', new ChildDefinition('c'));
448+
449+
$this->process($container);
450+
}
434451
}

0 commit comments

Comments
 (0)