Skip to content

Commit

Permalink
[DI] Fix dumping Doctrine-like service graphs (bis)
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolas-grekas committed Jul 29, 2019
1 parent 41ffa3e commit c694216
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 40 deletions.
Expand Up @@ -136,7 +136,7 @@ protected function processValue($value, $isRoot = false)
$this->lazy = false;

$byConstructor = $this->byConstructor;
$this->byConstructor = true;
$this->byConstructor = $isRoot || $byConstructor;
$this->processValue($value->getFactory());
$this->processValue($value->getArguments());
$this->byConstructor = $byConstructor;
Expand Down
87 changes: 54 additions & 33 deletions src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
Expand Up @@ -187,6 +187,7 @@ public function dump(array $options = [])
}
$this->container->getCompiler()->getServiceReferenceGraph()->clear();
$checkedNodes = [];
$this->singleUsePrivateIds = array_diff_key($this->singleUsePrivateIds, $this->circularReferences);

$this->docStar = $options['debug'] ? '*' : '';

Expand Down Expand Up @@ -338,10 +339,10 @@ private function getProxyDumper(): ProxyDumper
return $this->proxyDumper;
}

private function analyzeCircularReferences($sourceId, array $edges, &$checkedNodes, &$currentPath = [])
private function analyzeCircularReferences($sourceId, array $edges, &$checkedNodes, &$currentPath = [], $byConstructor = true)
{
$checkedNodes[$sourceId] = true;
$currentPath[$sourceId] = $sourceId;
$currentPath[$sourceId] = $byConstructor;

foreach ($edges as $edge) {
$node = $edge->getDestNode();
Expand All @@ -350,44 +351,52 @@ private function analyzeCircularReferences($sourceId, array $edges, &$checkedNod
if (!$node->getValue() instanceof Definition || $sourceId === $id || $edge->isLazy() || $edge->isWeak()) {
// no-op
} elseif (isset($currentPath[$id])) {
$currentId = $id;
foreach (array_reverse($currentPath) as $parentId) {
$this->circularReferences[$parentId][$currentId] = $currentId;
if ($parentId === $id) {
break;
}
$currentId = $parentId;
}
$this->addCircularReferences($id, $currentPath, $edge->isReferencedByConstructor());
} elseif (!isset($checkedNodes[$id])) {
$this->analyzeCircularReferences($id, $node->getOutEdges(), $checkedNodes, $currentPath);
$this->analyzeCircularReferences($id, $node->getOutEdges(), $checkedNodes, $currentPath, $edge->isReferencedByConstructor());
} elseif (isset($this->circularReferences[$id])) {
$this->connectCircularReferences($id, $currentPath);
$this->connectCircularReferences($id, $currentPath, $edge->isReferencedByConstructor());
}
}
unset($currentPath[$sourceId]);
}

private function connectCircularReferences($sourceId, &$currentPath, &$subPath = [])
private function connectCircularReferences($sourceId, &$currentPath, $byConstructor, &$subPath = [])
{
$subPath[$sourceId] = $sourceId;
$currentPath[$sourceId] = $sourceId;
$currentPath[$sourceId] = $subPath[$sourceId] = $byConstructor;

foreach ($this->circularReferences[$sourceId] as $id) {
foreach ($this->circularReferences[$sourceId] as $id => $byConstructor) {
if (isset($currentPath[$id])) {
$currentId = $id;
foreach (array_reverse($currentPath) as $parentId) {
$this->circularReferences[$parentId][$currentId] = $currentId;
if ($parentId === $id) {
break;
}
$currentId = $parentId;
}
$this->addCircularReferences($id, $currentPath, $byConstructor);
} elseif (!isset($subPath[$id]) && isset($this->circularReferences[$id])) {
$this->connectCircularReferences($id, $currentPath, $subPath);
$this->connectCircularReferences($id, $currentPath, $byConstructor, $subPath);
}
}
unset($currentPath[$sourceId]);
unset($subPath[$sourceId]);
unset($currentPath[$sourceId], $subPath[$sourceId]);
}

private function addCircularReferences($id, $currentPath, $byConstructor)
{
$currentPath[$id] = $byConstructor;
$circularRefs = [];

foreach (array_reverse($currentPath) as $parentId => $v) {
$byConstructor = $byConstructor && $v;
$circularRefs[] = $parentId;

if ($parentId === $id) {
break;
}
}

$currentId = $id;
foreach ($circularRefs as $parentId) {
if (empty($this->circularReferences[$parentId][$currentId])) {
$this->circularReferences[$parentId][$currentId] = $byConstructor;
}

$currentId = $parentId;
}
}

private function collectLineage($class, array &$lineage)
Expand Down Expand Up @@ -655,7 +664,6 @@ private function addService(string $id, Definition $definition): array
$autowired = $definition->isAutowired() ? ' autowired' : '';

if ($definition->isLazy()) {
unset($this->circularReferences[$id]);
$lazyInitialization = '$lazyLoad = true';
} else {
$lazyInitialization = '';
Expand Down Expand Up @@ -731,12 +739,12 @@ private function addInlineVariables(string $id, Definition $definition, array $a

private function addInlineReference(string $id, Definition $definition, string $targetId, bool $forConstructor): string
{
list($callCount, $behavior) = $this->serviceCalls[$targetId];

while ($this->container->hasAlias($targetId)) {
$targetId = (string) $this->container->getAlias($targetId);
}

list($callCount, $behavior) = $this->serviceCalls[$targetId];

if ($id === $targetId) {
return $this->addInlineService($id, $definition, $definition);
}
Expand All @@ -745,9 +753,13 @@ private function addInlineReference(string $id, Definition $definition, string $
return '';
}

$hasSelfRef = isset($this->circularReferences[$id][$targetId]);
$forConstructor = $forConstructor && !isset($this->definitionVariables[$definition]);
$code = $hasSelfRef && !$forConstructor ? $this->addInlineService($id, $definition, $definition) : '';
$hasSelfRef = isset($this->circularReferences[$id][$targetId]) && !isset($this->definitionVariables[$definition]);

if ($hasSelfRef && !$forConstructor && !$forConstructor = !$this->circularReferences[$id][$targetId]) {
$code = $this->addInlineService($id, $definition, $definition);
} else {
$code = '';
}

if (isset($this->referenceVariables[$targetId]) || (2 > $callCount && (!$hasSelfRef || !$forConstructor))) {
return $code;
Expand Down Expand Up @@ -1415,6 +1427,10 @@ private function getDefinitionsFromArguments(array $arguments, \SplObjectStorage
} elseif ($argument instanceof Reference) {
$id = (string) $argument;

while ($this->container->hasAlias($id)) {
$id = (string) $this->container->getAlias($id);
}

if (!isset($calls[$id])) {
$calls[$id] = [0, $argument->getInvalidBehavior()];
} else {
Expand Down Expand Up @@ -1548,6 +1564,11 @@ private function dumpValue($value, bool $interpolate = true): string
return '$'.$value;
} elseif ($value instanceof Reference) {
$id = (string) $value;

while ($this->container->hasAlias($id)) {
$id = (string) $this->container->getAlias($id);
}

if (null !== $this->referenceVariables && isset($this->referenceVariables[$id])) {
return $this->dumpValue($this->referenceVariables[$id], $interpolate);
}
Expand Down
Expand Up @@ -276,7 +276,7 @@ protected function getListener3Service()
*/
protected function getListener4Service()
{
$a = $this->getManager4Service();
$a = ($this->privates['manager4'] ?? $this->getManager4Service());

if (isset($this->services['listener4'])) {
return $this->services['listener4'];
Expand Down Expand Up @@ -345,7 +345,14 @@ protected function getManager2Service()
protected function getManager3Service($lazyLoad = true)
{
$a = new \stdClass();
$a->listener = [0 => ($this->services['listener3'] ?? $this->getListener3Service())];

$b = ($this->services['listener3'] ?? $this->getListener3Service());

if (isset($this->services['manager3'])) {
return $this->services['manager3'];
}

$a->listener = [0 => $b];

return $this->services['manager3'] = new \stdClass($a);
}
Expand Down Expand Up @@ -422,8 +429,11 @@ protected function getLevel5Service()
protected function getManager4Service($lazyLoad = true)
{
$a = new \stdClass();

$this->privates['manager4'] = $instance = new \stdClass($a);

$a->listener = [0 => ($this->services['listener4'] ?? $this->getListener4Service())];

return new \stdClass($a);
return $instance;
}
}
Expand Up @@ -404,7 +404,7 @@ protected function getListener3Service()
*/
protected function getListener4Service()
{
$a = $this->getManager4Service();
$a = ($this->privates['manager4'] ?? $this->getManager4Service());

if (isset($this->services['listener4'])) {
return $this->services['listener4'];
Expand Down Expand Up @@ -472,7 +472,13 @@ protected function getManager2Service()
*/
protected function getManager3Service($lazyLoad = true)
{
return $this->services['manager3'] = new \stdClass(($this->services['connection3'] ?? $this->getConnection3Service()));
$a = ($this->services['connection3'] ?? $this->getConnection3Service());

if (isset($this->services['manager3'])) {
return $this->services['manager3'];
}

return $this->services['manager3'] = new \stdClass($a);
}

/**
Expand Down Expand Up @@ -546,6 +552,12 @@ protected function getLevel5Service()
*/
protected function getManager4Service($lazyLoad = true)
{
return new \stdClass(($this->services['connection4'] ?? $this->getConnection4Service()));
$a = ($this->services['connection4'] ?? $this->getConnection4Service());

if (isset($this->privates['manager4'])) {
return $this->privates['manager4'];
}

return $this->privates['manager4'] = new \stdClass($a);
}
}

0 comments on commit c694216

Please sign in to comment.