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

Skip to content

Commit 73d9804

Browse files
bug #29247 [DI] fix taking lazy services into account when dumping the container (nicolas-grekas)
This PR was merged into the 3.4 branch. Discussion ---------- [DI] fix taking lazy services into account when dumping the container | Q | A | ------------- | --- | Branch? | 3.4 | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #29246 | License | MIT | Doc PR | - This PR fixes issues found while working on #29246. It *does* fix the infinite loop, ~but replaces it by an exception (reopening #29078)~: > ~It's a requirement to specify a Metadata Driver and pass it to Doctrine\ORM\Configuration::setMetadataDriverImpl()~ The full fix is not immediately accessible as it needs some core changes to the dumping logic. Requiring `symfony/proxy-manager-bridge` works around the issue properly. See #29251 for 4.2 Commits ------- 67d7623 [DI] fix taking lazy services into account when dumping the container
2 parents d0698b2 + 67d7623 commit 73d9804

File tree

6 files changed

+84
-29
lines changed

6 files changed

+84
-29
lines changed

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class AnalyzeServiceReferencesPass extends AbstractRecursivePass implements Repe
3737
private $hasProxyDumper;
3838
private $lazy;
3939
private $expressionLanguage;
40+
private $byConstructor;
4041

4142
/**
4243
* @param bool $onlyConstructorArguments Sets this Service Reference pass to ignore method calls
@@ -64,6 +65,7 @@ public function process(ContainerBuilder $container)
6465
$this->graph = $container->getCompiler()->getServiceReferenceGraph();
6566
$this->graph->clear();
6667
$this->lazy = false;
68+
$this->byConstructor = false;
6769

6870
foreach ($container->getAliases() as $id => $alias) {
6971
$targetId = $this->getDefinitionId((string) $alias);
@@ -100,7 +102,8 @@ protected function processValue($value, $isRoot = false)
100102
$targetDefinition,
101103
$value,
102104
$this->lazy || ($this->hasProxyDumper && $targetDefinition && $targetDefinition->isLazy()),
103-
ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $value->getInvalidBehavior()
105+
ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $value->getInvalidBehavior(),
106+
$this->byConstructor
104107
);
105108

106109
return $value;
@@ -118,8 +121,11 @@ protected function processValue($value, $isRoot = false)
118121
}
119122
$this->lazy = false;
120123

124+
$byConstructor = $this->byConstructor;
125+
$this->byConstructor = true;
121126
$this->processValue($value->getFactory());
122127
$this->processValue($value->getArguments());
128+
$this->byConstructor = $byConstructor;
123129

124130
if (!$this->onlyConstructorArguments) {
125131
$this->processValue($value->getProperties());

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,19 +91,21 @@ public function clear()
9191
* @param string $reference
9292
* @param bool $lazy
9393
* @param bool $weak
94+
* @param bool $byConstructor
9495
*/
95-
public function connect($sourceId, $sourceValue, $destId, $destValue = null, $reference = null/*, bool $lazy = false, bool $weak = false*/)
96+
public function connect($sourceId, $sourceValue, $destId, $destValue = null, $reference = null/*, bool $lazy = false, bool $weak = false, bool $byConstructor = false*/)
9697
{
9798
$lazy = \func_num_args() >= 6 ? func_get_arg(5) : false;
9899
$weak = \func_num_args() >= 7 ? func_get_arg(6) : false;
100+
$byConstructor = \func_num_args() >= 8 ? func_get_arg(7) : false;
99101

100102
if (null === $sourceId || null === $destId) {
101103
return;
102104
}
103105

104106
$sourceNode = $this->createNode($sourceId, $sourceValue);
105107
$destNode = $this->createNode($destId, $destValue);
106-
$edge = new ServiceReferenceGraphEdge($sourceNode, $destNode, $reference, $lazy, $weak);
108+
$edge = new ServiceReferenceGraphEdge($sourceNode, $destNode, $reference, $lazy, $weak, $byConstructor);
107109

108110
$sourceNode->addOutEdge($edge);
109111
$destNode->addInEdge($edge);

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

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,24 @@ class ServiceReferenceGraphEdge
2525
private $value;
2626
private $lazy;
2727
private $weak;
28+
private $byConstructor;
2829

2930
/**
3031
* @param ServiceReferenceGraphNode $sourceNode
3132
* @param ServiceReferenceGraphNode $destNode
3233
* @param mixed $value
3334
* @param bool $lazy
3435
* @param bool $weak
36+
* @param bool $byConstructor
3537
*/
36-
public function __construct(ServiceReferenceGraphNode $sourceNode, ServiceReferenceGraphNode $destNode, $value = null, $lazy = false, $weak = false)
38+
public function __construct(ServiceReferenceGraphNode $sourceNode, ServiceReferenceGraphNode $destNode, $value = null, $lazy = false, $weak = false, $byConstructor = false)
3739
{
3840
$this->sourceNode = $sourceNode;
3941
$this->destNode = $destNode;
4042
$this->value = $value;
4143
$this->lazy = $lazy;
4244
$this->weak = $weak;
45+
$this->byConstructor = $byConstructor;
4346
}
4447

4548
/**
@@ -91,4 +94,14 @@ public function isWeak()
9194
{
9295
return $this->weak;
9396
}
97+
98+
/**
99+
* Returns true if the edge links with a constructor argument.
100+
*
101+
* @return bool
102+
*/
103+
public function isReferencedByConstructor()
104+
{
105+
return $this->byConstructor;
106+
}
94107
}

src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -154,12 +154,16 @@ public function dump(array $options = array())
154154
}
155155
}
156156

157-
(new AnalyzeServiceReferencesPass(false))->process($this->container);
157+
(new AnalyzeServiceReferencesPass(false, !$this->getProxyDumper() instanceof NullDumper))->process($this->container);
158158
$this->circularReferences = array();
159-
$checkedNodes = array();
160-
foreach ($this->container->getCompiler()->getServiceReferenceGraph()->getNodes() as $id => $node) {
161-
$currentPath = array($id => $id);
162-
$this->analyzeCircularReferences($node->getOutEdges(), $checkedNodes, $currentPath);
159+
foreach (array(true, false) as $byConstructor) {
160+
foreach ($this->container->getCompiler()->getServiceReferenceGraph()->getNodes() as $id => $node) {
161+
if (!$node->getValue() instanceof Definition) {
162+
continue;
163+
}
164+
$currentPath = array($id => true);
165+
$this->analyzeCircularReferences($node->getOutEdges(), $currentPath, $id, $byConstructor);
166+
}
163167
}
164168
$this->container->getCompiler()->getServiceReferenceGraph()->clear();
165169

@@ -297,27 +301,31 @@ private function getProxyDumper()
297301
return $this->proxyDumper;
298302
}
299303

300-
private function analyzeCircularReferences(array $edges, &$checkedNodes, &$currentPath)
304+
private function analyzeCircularReferences(array $edges, &$currentPath, $sourceId, $byConstructor)
301305
{
302306
foreach ($edges as $edge) {
307+
if ($byConstructor && !$edge->isReferencedByConstructor()) {
308+
continue;
309+
}
303310
$node = $edge->getDestNode();
304311
$id = $node->getId();
305312

306-
if ($node->getValue() && ($edge->isLazy() || $edge->isWeak())) {
313+
if (!$node->getValue() instanceof Definition || $sourceId === $id || $edge->isLazy() || $edge->isWeak()) {
307314
// no-op
308315
} elseif (isset($currentPath[$id])) {
309316
$currentId = $id;
310317
foreach (array_reverse($currentPath) as $parentId) {
311-
$this->circularReferences[$parentId][$currentId] = $currentId;
318+
if (!isset($this->circularReferences[$parentId][$currentId])) {
319+
$this->circularReferences[$parentId][$currentId] = $byConstructor;
320+
}
312321
if ($parentId === $id) {
313322
break;
314323
}
315324
$currentId = $parentId;
316325
}
317-
} elseif (!isset($checkedNodes[$id])) {
318-
$checkedNodes[$id] = true;
326+
} else {
319327
$currentPath[$id] = $id;
320-
$this->analyzeCircularReferences($node->getOutEdges(), $checkedNodes, $currentPath);
328+
$this->analyzeCircularReferences($node->getOutEdges(), $currentPath, $id, $byConstructor);
321329
unset($currentPath[$id]);
322330
}
323331
}
@@ -700,8 +708,14 @@ private function addInlineVariables($id, Definition $definition, array $argument
700708

701709
private function addInlineReference($id, Definition $definition, $targetId, $forConstructor)
702710
{
711+
list($callCount, $behavior) = $this->serviceCalls[$targetId];
712+
713+
while ($this->container->hasAlias($targetId)) {
714+
$targetId = (string) $this->container->getAlias($targetId);
715+
}
716+
703717
if ($id === $targetId) {
704-
return $this->addInlineService($id, $definition, $definition, $forConstructor);
718+
return $this->addInlineService($id, $definition, $definition);
705719
}
706720

707721
if ('service_container' === $targetId || isset($this->referenceVariables[$targetId])) {
@@ -710,9 +724,7 @@ private function addInlineReference($id, Definition $definition, $targetId, $for
710724

711725
$hasSelfRef = isset($this->circularReferences[$id][$targetId]);
712726
$forConstructor = $forConstructor && !isset($this->definitionVariables[$definition]);
713-
list($callCount, $behavior) = $this->serviceCalls[$targetId];
714-
715-
$code = $hasSelfRef && !$forConstructor ? $this->addInlineService($id, $definition, $definition, $forConstructor) : '';
727+
$code = $hasSelfRef && $this->circularReferences[$id][$targetId] && !$forConstructor ? $this->addInlineService($id, $definition, $definition) : '';
716728

717729
if (isset($this->referenceVariables[$targetId]) || (2 > $callCount && (!$hasSelfRef || !$forConstructor))) {
718730
return $code;

src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_adawson.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,13 @@ protected function getHandler1Service()
133133
*/
134134
protected function getHandler2Service()
135135
{
136-
return $this->services['App\Handler2'] = new \App\Handler2(${($_ = isset($this->services['App\Db']) ? $this->services['App\Db'] : $this->getDbService()) && false ?: '_'}, ${($_ = isset($this->services['App\Schema']) ? $this->services['App\Schema'] : $this->getSchemaService()) && false ?: '_'}, ${($_ = isset($this->services['App\Processor']) ? $this->services['App\Processor'] : $this->getProcessorService()) && false ?: '_'});
136+
$a = ${($_ = isset($this->services['App\Processor']) ? $this->services['App\Processor'] : $this->getProcessorService()) && false ?: '_'};
137+
138+
if (isset($this->services['App\Handler2'])) {
139+
return $this->services['App\Handler2'];
140+
}
141+
142+
return $this->services['App\Handler2'] = new \App\Handler2(${($_ = isset($this->services['App\Db']) ? $this->services['App\Db'] : $this->getDbService()) && false ?: '_'}, ${($_ = isset($this->services['App\Schema']) ? $this->services['App\Schema'] : $this->getSchemaService()) && false ?: '_'}, $a);
137143
}
138144

139145
/**

src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_public.php

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -174,11 +174,16 @@ protected function getBaz6Service()
174174
*/
175175
protected function getConnectionService()
176176
{
177-
$a = new \stdClass();
177+
$a = ${($_ = isset($this->services['dispatcher']) ? $this->services['dispatcher'] : $this->getDispatcherService()) && false ?: '_'};
178+
179+
if (isset($this->services['connection'])) {
180+
return $this->services['connection'];
181+
}
182+
$b = new \stdClass();
178183

179-
$this->services['connection'] = $instance = new \stdClass(${($_ = isset($this->services['dispatcher']) ? $this->services['dispatcher'] : $this->getDispatcherService()) && false ?: '_'}, $a);
184+
$this->services['connection'] = $instance = new \stdClass($a, $b);
180185

181-
$a->logger = ${($_ = isset($this->services['logger']) ? $this->services['logger'] : $this->getLoggerService()) && false ?: '_'};
186+
$b->logger = ${($_ = isset($this->services['logger']) ? $this->services['logger'] : $this->getLoggerService()) && false ?: '_'};
182187

183188
return $instance;
184189
}
@@ -190,14 +195,19 @@ protected function getConnectionService()
190195
*/
191196
protected function getConnection2Service()
192197
{
193-
$a = new \stdClass();
198+
$a = ${($_ = isset($this->services['dispatcher2']) ? $this->services['dispatcher2'] : $this->getDispatcher2Service()) && false ?: '_'};
194199

195-
$this->services['connection2'] = $instance = new \stdClass(${($_ = isset($this->services['dispatcher2']) ? $this->services['dispatcher2'] : $this->getDispatcher2Service()) && false ?: '_'}, $a);
200+
if (isset($this->services['connection2'])) {
201+
return $this->services['connection2'];
202+
}
203+
$b = new \stdClass();
196204

197-
$b = new \stdClass($instance);
198-
$b->handler2 = new \stdClass(${($_ = isset($this->services['manager2']) ? $this->services['manager2'] : $this->getManager2Service()) && false ?: '_'});
205+
$this->services['connection2'] = $instance = new \stdClass($a, $b);
199206

200-
$a->logger2 = $b;
207+
$c = new \stdClass($instance);
208+
$c->handler2 = new \stdClass(${($_ = isset($this->services['manager2']) ? $this->services['manager2'] : $this->getManager2Service()) && false ?: '_'});
209+
210+
$b->logger2 = $c;
201211

202212
return $instance;
203213
}
@@ -431,7 +441,13 @@ protected function getRootService()
431441
*/
432442
protected function getSubscriberService()
433443
{
434-
return $this->services['subscriber'] = new \stdClass(${($_ = isset($this->services['manager']) ? $this->services['manager'] : $this->getManagerService()) && false ?: '_'});
444+
$a = ${($_ = isset($this->services['manager']) ? $this->services['manager'] : $this->getManagerService()) && false ?: '_'};
445+
446+
if (isset($this->services['subscriber'])) {
447+
return $this->services['subscriber'];
448+
}
449+
450+
return $this->services['subscriber'] = new \stdClass($a);
435451
}
436452

437453
/**

0 commit comments

Comments
 (0)