Skip to content

Commit 55d7218

Browse files
committed
Merge branch '2.7' into 2.8
* 2.7: Regression test for missing controller arguments fix a test checking for a value [Form][DX] FileType "multiple" fixes fixed CS [TwigBundle] Fix twig loader registered twice [Console] Fix wrong handling of multiline arg/opt descriptions [DependencyInjection] PhpDumper.php: hasReference() should not search references in lazy service arguments. [Form] fixed "empty_value" option deprecation
2 parents e2035e9 + fad7a7f commit 55d7218

File tree

4 files changed

+89
-6
lines changed

4 files changed

+89
-6
lines changed

Compiler/CheckCircularReferencesPass.php

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,18 @@ private function checkOutEdges(array $edges)
6060
$id = $node->getId();
6161

6262
if (empty($this->checkedNodes[$id])) {
63-
$searchKey = array_search($id, $this->currentPath);
64-
$this->currentPath[] = $id;
6563

66-
if (false !== $searchKey) {
67-
throw new ServiceCircularReferenceException($id, array_slice($this->currentPath, $searchKey));
68-
}
64+
// don't check circular dependencies for lazy services
65+
if (!$node->getValue() || !$node->getValue()->isLazy()) {
66+
$searchKey = array_search($id, $this->currentPath);
67+
$this->currentPath[] = $id;
68+
69+
if (false !== $searchKey) {
70+
throw new ServiceCircularReferenceException($id, array_slice($this->currentPath, $searchKey));
71+
}
6972

70-
$this->checkOutEdges($node->getOutEdges());
73+
$this->checkOutEdges($node->getOutEdges());
74+
}
7175

7276
$this->checkedNodes[$id] = true;
7377
array_pop($this->currentPath);

Dumper/PhpDumper.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1313,6 +1313,13 @@ private function hasReference($id, array $arguments, $deep = false, array &$visi
13131313
$visited[$argumentId] = true;
13141314

13151315
$service = $this->container->getDefinition($argumentId);
1316+
1317+
// if the proxy manager is enabled, disable searching for references in lazy services,
1318+
// as these services will be instantiated lazily and don't have direct related references.
1319+
if ($service->isLazy() && !$this->getProxyDumper() instanceof NullDumper) {
1320+
continue;
1321+
}
1322+
13161323
$arguments = array_merge($service->getMethodCalls(), $service->getArguments(), $service->getProperties());
13171324

13181325
if ($this->hasReference($id, $arguments, $deep, $visited)) {

Tests/Dumper/PhpDumperTest.php

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Component\DependencyInjection\Tests\Dumper;
1313

14+
use DummyProxyDumper;
1415
use Symfony\Component\DependencyInjection\ContainerBuilder;
1516
use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
1617
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
@@ -19,6 +20,8 @@
1920
use Symfony\Component\DependencyInjection\Variable;
2021
use Symfony\Component\ExpressionLanguage\Expression;
2122

23+
require_once __DIR__.'/../Fixtures/includes/classes.php';
24+
2225
class PhpDumperTest extends \PHPUnit_Framework_TestCase
2326
{
2427
protected static $fixturesPath;
@@ -294,4 +297,52 @@ public function testInitializePropertiesBeforeMethodCalls()
294297
$container = new \Symfony_DI_PhpDumper_Test_Properties_Before_Method_Calls();
295298
$this->assertTrue($container->get('bar')->callPassed(), '->dump() initializes properties before method calls');
296299
}
300+
301+
public function testCircularReferenceAllowanceForLazyServices()
302+
{
303+
$container = new ContainerBuilder();
304+
$container->register('foo', 'stdClass')->addArgument(new Reference('bar'));
305+
$container->register('bar', 'stdClass')->setLazy(true)->addArgument(new Reference('foo'));
306+
$container->compile();
307+
308+
$dumper = new PhpDumper($container);
309+
$dumper->dump();
310+
}
311+
312+
public function testCircularReferenceAllowanceForInlinedDefinitionsForLazyServices()
313+
{
314+
/*
315+
* test graph:
316+
* [connection] -> [event_manager] --> [entity_manager](lazy)
317+
* |
318+
* --(call)- addEventListener ("@lazy_service")
319+
*
320+
* [lazy_service](lazy) -> [entity_manager](lazy)
321+
*
322+
*/
323+
324+
$container = new ContainerBuilder();
325+
326+
$eventManagerDefinition = new Definition('stdClass');
327+
328+
$connectionDefinition = $container->register('connection', 'stdClass');
329+
$connectionDefinition->addArgument($eventManagerDefinition);
330+
331+
$container->register('entity_manager', 'stdClass')
332+
->setLazy(true)
333+
->addArgument(new Reference('connection'));
334+
335+
$lazyServiceDefinition = $container->register('lazy_service', 'stdClass');
336+
$lazyServiceDefinition->setLazy(true);
337+
$lazyServiceDefinition->addArgument(new Reference('entity_manager'));
338+
339+
$eventManagerDefinition->addMethodCall('addEventListener', array(new Reference('lazy_service')));
340+
341+
$container->compile();
342+
343+
$dumper = new PhpDumper($container);
344+
345+
$dumper->setProxyDumper(new DummyProxyDumper());
346+
$dumper->dump();
347+
}
297348
}

Tests/Fixtures/includes/classes.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
<?php
22

3+
use Symfony\Component\DependencyInjection\Definition;
4+
use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface as ProxyDumper;
5+
36
function sc_configure($instance)
47
{
58
$instance->configure();
@@ -76,3 +79,21 @@ public function callPassed()
7679
return $this->callPassed;
7780
}
7881
}
82+
83+
class DummyProxyDumper implements ProxyDumper
84+
{
85+
public function isProxyCandidate(Definition $definition)
86+
{
87+
return false;
88+
}
89+
90+
public function getProxyFactoryCode(Definition $definition, $id)
91+
{
92+
return '';
93+
}
94+
95+
public function getProxyCode(Definition $definition)
96+
{
97+
return '';
98+
}
99+
}

0 commit comments

Comments
 (0)