[DependencyInjection] PhpDumper.php: hasReference() should not search references in lazy service arguments.

This commit is contained in:
Antanas Arvasevicius 2016-09-10 20:39:00 +03:00
parent 777cdfc0f6
commit 595a9781e2
4 changed files with 99 additions and 6 deletions

View File

@ -60,15 +60,20 @@ class CheckCircularReferencesPass implements CompilerPassInterface
$id = $node->getId();
if (empty($this->checkedNodes[$id])) {
$searchKey = array_search($id, $this->currentPath);
$this->currentPath[] = $id;
if (false !== $searchKey) {
throw new ServiceCircularReferenceException($id, array_slice($this->currentPath, $searchKey));
// * don't check circular dependencies in lazy services.
$isLazy = $node->getValue() && $node->getValue()->isLazy();
if (!$isLazy) {
$searchKey = array_search($id, $this->currentPath);
$this->currentPath[] = $id;
if (false !== $searchKey) {
throw new ServiceCircularReferenceException($id, array_slice($this->currentPath, $searchKey));
}
$this->checkOutEdges($node->getOutEdges());
}
$this->checkOutEdges($node->getOutEdges());
$this->checkedNodes[$id] = true;
array_pop($this->currentPath);
}

View File

@ -1293,6 +1293,13 @@ EOF;
$visited[$argumentId] = true;
$service = $this->container->getDefinition($argumentId);
// if exists proxy dumper (proxy-manager) don't search references in lazy services.
// As these services will be instantiated lazily and don't have direct related references.
if ($service->isLazy() && !($this->getProxyDumper() instanceof NullDumper)) {
continue;
}
$arguments = array_merge($service->getMethodCalls(), $service->getArguments(), $service->getProperties());
if ($this->hasReference($id, $arguments, $deep, $visited)) {

View File

@ -11,6 +11,7 @@
namespace Symfony\Component\DependencyInjection\Tests\Dumper;
use DummyProxyDumper;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
@ -19,6 +20,8 @@ use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Variable;
use Symfony\Component\ExpressionLanguage\Expression;
require_once __DIR__.'/../Fixtures/includes/classes.php';
class PhpDumperTest extends \PHPUnit_Framework_TestCase
{
protected static $fixturesPath;
@ -286,4 +289,52 @@ class PhpDumperTest extends \PHPUnit_Framework_TestCase
$container = new \Symfony_DI_PhpDumper_Test_Properties_Before_Method_Calls();
$this->assertTrue($container->get('bar')->callPassed(), '->dump() initializes properties before method calls');
}
public function testCircularReferenceAllowanceForLazyServices()
{
$container = new ContainerBuilder();
$container->register('foo', 'stdClass')->addArgument(new Reference('bar'));
$container->register('bar', 'stdClass')->setLazy(true)->addArgument(new Reference('foo'));
$container->compile();
$dumper = new PhpDumper($container);
$dumper->dump();
}
public function testCircularReferenceAllowanceForInlinedDefinitionsForLazyServices()
{
/*
* test graph:
* [connection] -> [event_manager] --> [entity_manager](lazy)
* |
* --(call)- addEventListener ("@lazy_service")
*
* [lazy_service](lazy) -> [entity_manager](lazy)
*
*/
$container = new ContainerBuilder();
$eventManagerDefinition = new Definition('stdClass');
$connectionDefinition = $container->register('connection', 'stdClass');
$connectionDefinition->addArgument($eventManagerDefinition);
$container->register('entity_manager', 'stdClass')
->setLazy(true)
->addArgument(new Reference('connection'));
$lazyServiceDefinition = $container->register('lazy_service', 'stdClass');
$lazyServiceDefinition->setLazy(true);
$lazyServiceDefinition->addArgument(new Reference('entity_manager'));
$eventManagerDefinition->addMethodCall('addEventListener', array(new Reference('lazy_service')));
$container->compile();
$dumper = new PhpDumper($container);
$dumper->setProxyDumper(new DummyProxyDumper());
$dumper->dump();
}
}

View File

@ -1,5 +1,8 @@
<?php
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface as ProxyDumper;
function sc_configure($instance)
{
$instance->configure();
@ -76,3 +79,30 @@ class MethodCallClass
return $this->callPassed;
}
}
class DummyProxyDumper implements ProxyDumper
{
/**
* {@inheritdoc}
*/
public function isProxyCandidate(Definition $definition)
{
return false;
}
/**
* {@inheritdoc}
*/
public function getProxyFactoryCode(Definition $definition, $id)
{
return '';
}
/**
* {@inheritdoc}
*/
public function getProxyCode(Definition $definition)
{
return '';
}
}