Skip to content

Commit 93aedf1

Browse files
Merge branch '3.1' into 3.2
* 3.1: (28 commits) Fix merge [Validator] add class name to the cache key [Serializer] Remove AbstractObjectNormalizer::isAttributeToNormalize Throw less misleading exception when property access not found [Twig] Fix deprecations with Twig 1.29 Fixed typo [FrameworkBundle] Removed the kernel.debug parameter from the cache pool namespace seed Fix email address fix the docblock in regard to the role argument Don't use the "app" global variable in the profiler [VarDumper] fix tests when xdebug is enabled Fix merge FIXED NON EXISTING TYPE DECLARATION [Cache] Fix dumping SplDoublyLinkedList iter mode [Console] fixed PHP7 Errors when not using Dispatcher Regression test for missing controller arguments (3.1) Regression test for missing controller arguments fix a test checking for a value [Form][DX] FileType "multiple" fixes fixed CS ...
2 parents f5419ad + bd2a915 commit 93aedf1

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

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

13151322
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\Config\FileLocator;
1516
use Symfony\Component\DependencyInjection\ContainerBuilder;
1617
use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
@@ -21,6 +22,8 @@
2122
use Symfony\Component\DependencyInjection\Variable;
2223
use Symfony\Component\ExpressionLanguage\Expression;
2324

25+
require_once __DIR__.'/../Fixtures/includes/classes.php';
26+
2427
class PhpDumperTest extends \PHPUnit_Framework_TestCase
2528
{
2629
protected static $fixturesPath;
@@ -340,4 +343,52 @@ public function testInitializePropertiesBeforeMethodCalls()
340343
$container = new \Symfony_DI_PhpDumper_Test_Properties_Before_Method_Calls();
341344
$this->assertTrue($container->get('bar')->callPassed(), '->dump() initializes properties before method calls');
342345
}
346+
347+
public function testCircularReferenceAllowanceForLazyServices()
348+
{
349+
$container = new ContainerBuilder();
350+
$container->register('foo', 'stdClass')->addArgument(new Reference('bar'));
351+
$container->register('bar', 'stdClass')->setLazy(true)->addArgument(new Reference('foo'));
352+
$container->compile();
353+
354+
$dumper = new PhpDumper($container);
355+
$dumper->dump();
356+
}
357+
358+
public function testCircularReferenceAllowanceForInlinedDefinitionsForLazyServices()
359+
{
360+
/*
361+
* test graph:
362+
* [connection] -> [event_manager] --> [entity_manager](lazy)
363+
* |
364+
* --(call)- addEventListener ("@lazy_service")
365+
*
366+
* [lazy_service](lazy) -> [entity_manager](lazy)
367+
*
368+
*/
369+
370+
$container = new ContainerBuilder();
371+
372+
$eventManagerDefinition = new Definition('stdClass');
373+
374+
$connectionDefinition = $container->register('connection', 'stdClass');
375+
$connectionDefinition->addArgument($eventManagerDefinition);
376+
377+
$container->register('entity_manager', 'stdClass')
378+
->setLazy(true)
379+
->addArgument(new Reference('connection'));
380+
381+
$lazyServiceDefinition = $container->register('lazy_service', 'stdClass');
382+
$lazyServiceDefinition->setLazy(true);
383+
$lazyServiceDefinition->addArgument(new Reference('entity_manager'));
384+
385+
$eventManagerDefinition->addMethodCall('addEventListener', array(new Reference('lazy_service')));
386+
387+
$container->compile();
388+
389+
$dumper = new PhpDumper($container);
390+
391+
$dumper->setProxyDumper(new DummyProxyDumper());
392+
$dumper->dump();
393+
}
343394
}

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
@@ -571,4 +571,13 @@ public function testAliasDefinitionContainsUnsupportedElements()
571571

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

0 commit comments

Comments
 (0)