Skip to content

Commit bd2a915

Browse files
Merge branch '2.8' into 3.1
* 2.8: [Twig] Fix deprecations with Twig 1.29 Fixed typo Fix email address fix the docblock in regard to the role argument [VarDumper] fix tests when xdebug is enabled Fix merge [Cache] Fix dumping SplDoublyLinkedList iter mode [Console] fixed PHP7 Errors when not using Dispatcher 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 [WebProfilerBundle] Fix dump block is unfairly restrained [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 Cast result to int before adding to it
2 parents 268b752 + 51a7b53 commit bd2a915

File tree

7 files changed

+119
-17
lines changed

7 files changed

+119
-17
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
@@ -1201,6 +1201,13 @@ private function hasReference($id, array $arguments, $deep = false, array &$visi
12011201
$visited[$argumentId] = true;
12021202

12031203
$service = $this->container->getDefinition($argumentId);
1204+
1205+
// if the proxy manager is enabled, disable searching for references in lazy services,
1206+
// as these services will be instantiated lazily and don't have direct related references.
1207+
if ($service->isLazy() && !$this->getProxyDumper() instanceof NullDumper) {
1208+
continue;
1209+
}
1210+
12041211
$arguments = array_merge($service->getMethodCalls(), $service->getArguments(), $service->getProperties());
12051212

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

Loader/XmlFileLoader.php

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -346,21 +346,22 @@ private function getArgumentsAsPhp(\DOMElement $node, $name, $lowercase = true)
346346
$arg->setAttribute('key', $arg->getAttribute('name'));
347347
}
348348

349-
if (!$arg->hasAttribute('key')) {
350-
$key = !$arguments ? 0 : max(array_keys($arguments)) + 1;
351-
} else {
352-
$key = $arg->getAttribute('key');
353-
}
354-
355-
// parameter keys are case insensitive
356-
if ('parameter' == $name && $lowercase) {
357-
$key = strtolower($key);
358-
}
359-
360349
// this is used by DefinitionDecorator to overwrite a specific
361350
// argument of the parent definition
362351
if ($arg->hasAttribute('index')) {
363352
$key = 'index_'.$arg->getAttribute('index');
353+
} elseif (!$arg->hasAttribute('key')) {
354+
// Append an empty argument, then fetch its key to overwrite it later
355+
$arguments[] = null;
356+
$keys = array_keys($arguments);
357+
$key = array_pop($keys);
358+
} else {
359+
$key = $arg->getAttribute('key');
360+
361+
// parameter keys are case insensitive
362+
if ('parameter' == $name && $lowercase) {
363+
$key = strtolower($key);
364+
}
364365
}
365366

366367
switch ($arg->getAttribute('type')) {

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;
@@ -314,4 +317,52 @@ public function testInitializePropertiesBeforeMethodCalls()
314317
$container = new \Symfony_DI_PhpDumper_Test_Properties_Before_Method_Calls();
315318
$this->assertTrue($container->get('bar')->callPassed(), '->dump() initializes properties before method calls');
316319
}
320+
321+
public function testCircularReferenceAllowanceForLazyServices()
322+
{
323+
$container = new ContainerBuilder();
324+
$container->register('foo', 'stdClass')->addArgument(new Reference('bar'));
325+
$container->register('bar', 'stdClass')->setLazy(true)->addArgument(new Reference('foo'));
326+
$container->compile();
327+
328+
$dumper = new PhpDumper($container);
329+
$dumper->dump();
330+
}
331+
332+
public function testCircularReferenceAllowanceForInlinedDefinitionsForLazyServices()
333+
{
334+
/*
335+
* test graph:
336+
* [connection] -> [event_manager] --> [entity_manager](lazy)
337+
* |
338+
* --(call)- addEventListener ("@lazy_service")
339+
*
340+
* [lazy_service](lazy) -> [entity_manager](lazy)
341+
*
342+
*/
343+
344+
$container = new ContainerBuilder();
345+
346+
$eventManagerDefinition = new Definition('stdClass');
347+
348+
$connectionDefinition = $container->register('connection', 'stdClass');
349+
$connectionDefinition->addArgument($eventManagerDefinition);
350+
351+
$container->register('entity_manager', 'stdClass')
352+
->setLazy(true)
353+
->addArgument(new Reference('connection'));
354+
355+
$lazyServiceDefinition = $container->register('lazy_service', 'stdClass');
356+
$lazyServiceDefinition->setLazy(true);
357+
$lazyServiceDefinition->addArgument(new Reference('entity_manager'));
358+
359+
$eventManagerDefinition->addMethodCall('addEventListener', array(new Reference('lazy_service')));
360+
361+
$container->compile();
362+
363+
$dumper = new PhpDumper($container);
364+
365+
$dumper->setProxyDumper(new DummyProxyDumper());
366+
$dumper->dump();
367+
}
317368
}

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+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
3+
<services>
4+
<service id="foo" class="Foo">
5+
<argument key="type">foo</argument>
6+
<argument>bar</argument>
7+
</service>
8+
</services>
9+
</container>

Tests/Loader/XmlFileLoaderTest.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,4 +570,13 @@ public function testAliasDefinitionContainsUnsupportedElements()
570570

571571
$this->assertTrue($container->has('bar'));
572572
}
573+
574+
public function testArgumentWithKeyOutsideCollection()
575+
{
576+
$container = new ContainerBuilder();
577+
$loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml'));
578+
$loader->load('with_key_outside_collection.xml');
579+
580+
$this->assertSame(array('type' => 'foo', 'bar'), $container->getDefinition('foo')->getArguments());
581+
}
573582
}

0 commit comments

Comments
 (0)