Merge branch '3.4' into 4.1

* 3.4:
  [DI] fix analyzing lazy refs involved in circular loops
This commit is contained in:
Nicolas Grekas 2018-08-08 13:48:00 +02:00
commit a31b5d0ee3
3 changed files with 16 additions and 23 deletions

View File

@ -34,15 +34,17 @@ class AnalyzeServiceReferencesPass extends AbstractRecursivePass implements Repe
private $graph; private $graph;
private $currentDefinition; private $currentDefinition;
private $onlyConstructorArguments; private $onlyConstructorArguments;
private $hasProxyDumper;
private $lazy; private $lazy;
private $expressionLanguage; private $expressionLanguage;
/** /**
* @param bool $onlyConstructorArguments Sets this Service Reference pass to ignore method calls * @param bool $onlyConstructorArguments Sets this Service Reference pass to ignore method calls
*/ */
public function __construct(bool $onlyConstructorArguments = false) public function __construct(bool $onlyConstructorArguments = false, bool $hasProxyDumper = true)
{ {
$this->onlyConstructorArguments = $onlyConstructorArguments; $this->onlyConstructorArguments = $onlyConstructorArguments;
$this->hasProxyDumper = $hasProxyDumper;
} }
/** /**
@ -97,7 +99,7 @@ class AnalyzeServiceReferencesPass extends AbstractRecursivePass implements Repe
$targetId, $targetId,
$targetDefinition, $targetDefinition,
$value, $value,
$this->lazy || ($targetDefinition && $targetDefinition->isLazy()), $this->lazy || ($this->hasProxyDumper && $targetDefinition && $targetDefinition->isLazy()),
ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $value->getInvalidBehavior() ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $value->getInvalidBehavior()
); );

View File

@ -15,6 +15,7 @@ use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\Compiler\AnalyzeServiceReferencesPass; use Symfony\Component\DependencyInjection\Compiler\AnalyzeServiceReferencesPass;
use Symfony\Component\DependencyInjection\Compiler\CheckCircularReferencesPass;
use Symfony\Component\DependencyInjection\Container; use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface;
@ -140,29 +141,19 @@ class PhpDumper extends Dumper
$this->initializeMethodNamesMap('Container' === $baseClass ? Container::class : $baseClass); $this->initializeMethodNamesMap('Container' === $baseClass ? Container::class : $baseClass);
if ($this->getProxyDumper() instanceof NullDumper) { if ($this->getProxyDumper() instanceof NullDumper) {
(new AnalyzeServiceReferencesPass(true))->process($this->container); (new AnalyzeServiceReferencesPass(true, false))->process($this->container);
$this->circularReferences = array(); try {
$checkedNodes = array(); (new CheckCircularReferencesPass())->process($this->container);
foreach ($this->container->getCompiler()->getServiceReferenceGraph()->getNodes() as $id => $node) { } catch (ServiceCircularReferenceException $e) {
$currentPath = array($id => $id); $path = $e->getPath();
$this->analyzeCircularReferences($node->getOutEdges(), $checkedNodes, $currentPath); end($path);
} $path[key($path)] .= '". Try running "composer require symfony/proxy-manager-bridge';
foreach ($this->circularReferences as $parent => $ids) {
$path = array($parent);
while (!isset($ids[$parent])) {
foreach ($ids as $id) {
$path[] = $id;
$ids = $this->circularReferences[$id];
break;
}
}
$path[] = $parent.'". Try running "composer require symfony/proxy-manager-bridge';
throw new ServiceCircularReferenceException($parent, $path); throw new ServiceCircularReferenceException($e->getServiceId(), $path);
} }
} }
(new AnalyzeServiceReferencesPass())->process($this->container); (new AnalyzeServiceReferencesPass(false, !$this->getProxyDumper() instanceof NullDumper))->process($this->container);
$this->circularReferences = array(); $this->circularReferences = array();
$checkedNodes = array(); $checkedNodes = array();
foreach ($this->container->getCompiler()->getServiceReferenceGraph()->getNodes() as $id => $node) { foreach ($this->container->getCompiler()->getServiceReferenceGraph()->getNodes() as $id => $node) {
@ -369,7 +360,7 @@ EOTXT
$node = $edge->getDestNode(); $node = $edge->getDestNode();
$id = $node->getId(); $id = $node->getId();
if ($node->getValue() && (($edge->isLazy() && !$this->getProxyDumper() instanceof NullDumper) || $edge->isWeak())) { if ($node->getValue() && ($edge->isLazy() || $edge->isWeak())) {
// no-op // no-op
} elseif (isset($currentPath[$id])) { } elseif (isset($currentPath[$id])) {
foreach (array_reverse($currentPath) as $parentId) { foreach (array_reverse($currentPath) as $parentId) {

View File

@ -578,7 +578,7 @@ class PhpDumperTest extends TestCase
$dumper = new PhpDumper($container); $dumper = new PhpDumper($container);
$message = 'Circular reference detected for service "bar", path: "bar -> foo -> bar". Try running "composer require symfony/proxy-manager-bridge".'; $message = 'Circular reference detected for service "foo", path: "foo -> bar -> foo". Try running "composer require symfony/proxy-manager-bridge".';
if (method_exists($this, 'expectException')) { if (method_exists($this, 'expectException')) {
$this->expectException(ServiceCircularReferenceException::class); $this->expectException(ServiceCircularReferenceException::class);
$this->expectExceptionMessage($message); $this->expectExceptionMessage($message);