Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit c173714

Browse filesBrowse files
tgalopinnicolas-grekas
authored andcommitted
[DependencyInjection] Implement lazy collection type using generators
1 parent d0e8476 commit c173714
Copy full SHA for c173714

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Dismiss banner

42 files changed

+521
-15
lines changed
+27Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\DependencyInjection\Argument;
13+
14+
/**
15+
* Represents a complex argument containing nested values.
16+
*
17+
* @author Titouan Galopin <galopintitouan@gmail.com>
18+
*/
19+
interface ArgumentInterface
20+
{
21+
/**
22+
* @return array
23+
*/
24+
public function getValues();
25+
26+
public function setValues(array $values);
27+
}
+43Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\DependencyInjection\Argument;
13+
14+
/**
15+
* Represents a collection of values to lazily iterate over.
16+
*
17+
* @author Titouan Galopin <galopintitouan@gmail.com>
18+
*/
19+
class IteratorArgument implements ArgumentInterface
20+
{
21+
private $values;
22+
23+
public function __construct(array $values)
24+
{
25+
$this->values = $values;
26+
}
27+
28+
/**
29+
* @return array The values to lazily iterate over
30+
*/
31+
public function getValues()
32+
{
33+
return $this->values;
34+
}
35+
36+
/**
37+
* @param array $values The values to lazily iterate over
38+
*/
39+
public function setValues(array $values)
40+
{
41+
$this->values = $values;
42+
}
43+
}
+32Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\DependencyInjection\Argument;
13+
14+
/**
15+
* @internal
16+
*/
17+
class RewindableGenerator implements \IteratorAggregate
18+
{
19+
private $generator;
20+
21+
public function __construct(callable $generator)
22+
{
23+
$this->generator = $generator;
24+
}
25+
26+
public function getIterator()
27+
{
28+
$g = $this->generator;
29+
30+
return $g();
31+
}
32+
}

‎src/Symfony/Component/DependencyInjection/Compiler/AnalyzeServiceReferencesPass.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/AnalyzeServiceReferencesPass.php
+11-4Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Component\DependencyInjection\Compiler;
1313

14+
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
1415
use Symfony\Component\DependencyInjection\Definition;
1516
use Symfony\Component\DependencyInjection\Reference;
1617
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -91,19 +92,25 @@ public function process(ContainerBuilder $container)
9192
* Processes service definitions for arguments to find relationships for the service graph.
9293
*
9394
* @param array $arguments An array of Reference or Definition objects relating to service definitions
95+
* @param bool $lazy Whether the references nested in the arguments should be considered lazy or not
9496
*/
95-
private function processArguments(array $arguments)
97+
private function processArguments(array $arguments, $lazy = false)
9698
{
9799
foreach ($arguments as $argument) {
98100
if (is_array($argument)) {
99-
$this->processArguments($argument);
101+
$this->processArguments($argument, $lazy);
102+
} elseif ($argument instanceof ArgumentInterface) {
103+
$this->processArguments($argument->getValues(), true);
100104
} elseif ($argument instanceof Reference) {
105+
$targetDefinition = $this->getDefinition((string) $argument);
106+
101107
$this->graph->connect(
102108
$this->currentId,
103109
$this->currentDefinition,
104110
$this->getDefinitionId((string) $argument),
105-
$this->getDefinition((string) $argument),
106-
$argument
111+
$targetDefinition,
112+
$argument,
113+
$lazy || ($targetDefinition && $targetDefinition->isLazy())
107114
);
108115
} elseif ($argument instanceof Definition) {
109116
$this->processArguments($argument->getArguments());

‎src/Symfony/Component/DependencyInjection/Compiler/CheckCircularReferencesPass.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/CheckCircularReferencesPass.php
+2-3Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,8 @@ private function checkOutEdges(array $edges)
6060
$id = $node->getId();
6161

6262
if (empty($this->checkedNodes[$id])) {
63-
64-
// don't check circular dependencies for lazy services
65-
if (!$node->getValue() || !$node->getValue()->isLazy()) {
63+
// Don't check circular references for lazy edges
64+
if (!$node->getValue() || !$edge->isLazy()) {
6665
$searchKey = array_search($id, $this->currentPath);
6766
$this->currentPath[] = $id;
6867

‎src/Symfony/Component/DependencyInjection/Compiler/CheckExceptionOnInvalidReferenceBehaviorPass.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/CheckExceptionOnInvalidReferenceBehaviorPass.php
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Component\DependencyInjection\Compiler;
1313

14+
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
1415
use Symfony\Component\DependencyInjection\Definition;
1516
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
1617
use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -49,6 +50,8 @@ private function processReferences(array $arguments)
4950
foreach ($arguments as $argument) {
5051
if (is_array($argument)) {
5152
$this->processReferences($argument);
53+
} elseif ($argument instanceof ArgumentInterface) {
54+
$this->processReferences($argument->getValues());
5255
} elseif ($argument instanceof Definition) {
5356
$this->processDefinition($argument);
5457
} elseif ($argument instanceof Reference && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE === $argument->getInvalidBehavior()) {

‎src/Symfony/Component/DependencyInjection/Compiler/CheckReferenceValidityPass.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/CheckReferenceValidityPass.php
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Component\DependencyInjection\Compiler;
1313

14+
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
1415
use Symfony\Component\DependencyInjection\Definition;
1516
use Symfony\Component\DependencyInjection\Reference;
1617
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -63,6 +64,8 @@ private function validateReferences(array $arguments)
6364
foreach ($arguments as $argument) {
6465
if (is_array($argument)) {
6566
$this->validateReferences($argument);
67+
} elseif ($argument instanceof ArgumentInterface) {
68+
$this->validateReferences($argument->getValues());
6669
} elseif ($argument instanceof Reference) {
6770
$targetDefinition = $this->getDefinition((string) $argument);
6871

‎src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Component\DependencyInjection\Compiler;
1313

14+
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
1415
use Symfony\Component\DependencyInjection\Definition;
1516
use Symfony\Component\DependencyInjection\Reference;
1617
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -67,6 +68,8 @@ private function inlineArguments(ContainerBuilder $container, array $arguments,
6768
}
6869
if (is_array($argument)) {
6970
$arguments[$k] = $this->inlineArguments($container, $argument);
71+
} elseif ($argument instanceof ArgumentInterface) {
72+
$argument->setValues($this->inlineArguments($container, $argument->getValues()));
7073
} elseif ($argument instanceof Reference) {
7174
if (!$container->hasDefinition($id = (string) $argument)) {
7275
continue;

‎src/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Component\DependencyInjection\Compiler;
1313

14+
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
1415
use Symfony\Component\DependencyInjection\ContainerBuilder;
1516
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
1617
use Symfony\Component\DependencyInjection\Reference;
@@ -98,6 +99,10 @@ private function updateArgumentReferences(array $replacements, $definitionId, ar
9899
$arguments[$k] = $this->updateArgumentReferences($replacements, $definitionId, $argument);
99100
continue;
100101
}
102+
if ($argument instanceof ArgumentInterface) {
103+
$argument->setValues($this->updateArgumentReferences($replacements, $definitionId, $argument->getValues()));
104+
continue;
105+
}
101106
// Skip arguments that don't need replacement
102107
if (!$argument instanceof Reference) {
103108
continue;

‎src/Symfony/Component/DependencyInjection/Compiler/ResolveDefinitionTemplatesPass.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/ResolveDefinitionTemplatesPass.php
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Component\DependencyInjection\Compiler;
1313

14+
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
1415
use Symfony\Component\DependencyInjection\ChildDefinition;
1516
use Symfony\Component\DependencyInjection\Definition;
1617
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -63,6 +64,8 @@ private function resolveArguments(ContainerBuilder $container, array $arguments,
6364
}
6465
if (is_array($argument)) {
6566
$arguments[$k] = $this->resolveArguments($container, $argument);
67+
} elseif ($argument instanceof ArgumentInterface) {
68+
$argument->setValues($this->resolveArguments($container, $argument->getValues()));
6669
} elseif ($argument instanceof Definition) {
6770
if ($argument instanceof ChildDefinition) {
6871
$arguments[$k] = $argument = $this->resolveDefinition($container, $argument);

‎src/Symfony/Component/DependencyInjection/Compiler/ResolveInvalidReferencesPass.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/ResolveInvalidReferencesPass.php
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Component\DependencyInjection\Compiler;
1313

14+
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
1415
use Symfony\Component\DependencyInjection\ContainerInterface;
1516
use Symfony\Component\DependencyInjection\Reference;
1617
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -84,6 +85,8 @@ private function processArguments(array $arguments, $inMethodCall = false, $inCo
8485
foreach ($arguments as $k => $argument) {
8586
if (is_array($argument)) {
8687
$arguments[$k] = $this->processArguments($argument, $inMethodCall, true);
88+
} elseif ($argument instanceof ArgumentInterface) {
89+
$argument->setValues($this->processArguments($argument->getValues(), $inMethodCall, true));
8790
} elseif ($argument instanceof Reference) {
8891
$id = (string) $argument;
8992

‎src/Symfony/Component/DependencyInjection/Compiler/ResolveReferencesToAliasesPass.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/ResolveReferencesToAliasesPass.php
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Component\DependencyInjection\Compiler;
1313

14+
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
1415
use Symfony\Component\DependencyInjection\Alias;
1516
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
1617
use Symfony\Component\DependencyInjection\Reference;
@@ -65,6 +66,8 @@ private function processArguments(array $arguments)
6566
foreach ($arguments as $k => $argument) {
6667
if (is_array($argument)) {
6768
$arguments[$k] = $this->processArguments($argument);
69+
} elseif ($argument instanceof ArgumentInterface) {
70+
$argument->setValues($this->processArguments($argument->getValues()));
6871
} elseif ($argument instanceof Reference) {
6972
$defId = $this->getDefinitionId($id = (string) $argument);
7073

‎src/Symfony/Component/DependencyInjection/Compiler/ServiceReferenceGraph.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/ServiceReferenceGraph.php
+3-2Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,13 @@ public function clear()
8484
* @param string $destId
8585
* @param string $destValue
8686
* @param string $reference
87+
* @param bool $lazy
8788
*/
88-
public function connect($sourceId, $sourceValue, $destId, $destValue = null, $reference = null)
89+
public function connect($sourceId, $sourceValue, $destId, $destValue = null, $reference = null, $lazy = false)
8990
{
9091
$sourceNode = $this->createNode($sourceId, $sourceValue);
9192
$destNode = $this->createNode($destId, $destValue);
92-
$edge = new ServiceReferenceGraphEdge($sourceNode, $destNode, $reference);
93+
$edge = new ServiceReferenceGraphEdge($sourceNode, $destNode, $reference, $lazy);
9394

9495
$sourceNode->addOutEdge($edge);
9596
$destNode->addInEdge($edge);

‎src/Symfony/Component/DependencyInjection/Compiler/ServiceReferenceGraphEdge.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/ServiceReferenceGraphEdge.php
+14-1Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,20 @@ class ServiceReferenceGraphEdge
2323
private $sourceNode;
2424
private $destNode;
2525
private $value;
26+
private $lazy;
2627

2728
/**
2829
* @param ServiceReferenceGraphNode $sourceNode
2930
* @param ServiceReferenceGraphNode $destNode
3031
* @param string $value
32+
* @param bool $lazy
3133
*/
32-
public function __construct(ServiceReferenceGraphNode $sourceNode, ServiceReferenceGraphNode $destNode, $value = null)
34+
public function __construct(ServiceReferenceGraphNode $sourceNode, ServiceReferenceGraphNode $destNode, $value = null, $lazy = false)
3335
{
3436
$this->sourceNode = $sourceNode;
3537
$this->destNode = $destNode;
3638
$this->value = $value;
39+
$this->lazy = $lazy;
3740
}
3841

3942
/**
@@ -65,4 +68,14 @@ public function getDestNode()
6568
{
6669
return $this->destNode;
6770
}
71+
72+
/**
73+
* Returns true if the edge is lazy, meaning it's a dependency not requiring direct instantiation.
74+
*
75+
* @return bool
76+
*/
77+
public function isLazy()
78+
{
79+
return $this->lazy;
80+
}
6881
}

‎src/Symfony/Component/DependencyInjection/ContainerBuilder.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/ContainerBuilder.php
+16-1Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
namespace Symfony\Component\DependencyInjection;
1313

14+
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
15+
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
1416
use Symfony\Component\DependencyInjection\Compiler\Compiler;
1517
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
1618
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
@@ -96,7 +98,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
9698
private $envPlaceholders = array();
9799

98100
/**
99-
* @var int[] A map of env vars to their resolution counter.
101+
* @var int[] A map of env vars to their resolution counter
100102
*/
101103
private $envCounters = array();
102104

@@ -961,6 +963,19 @@ public function resolveServices($value)
961963
foreach ($value as $k => $v) {
962964
$value[$k] = $this->resolveServices($v);
963965
}
966+
} elseif ($value instanceof IteratorArgument) {
967+
$parameterBag = $this->getParameterBag();
968+
$value = new RewindableGenerator(function () use ($value, $parameterBag) {
969+
foreach ($value->getValues() as $k => $v) {
970+
foreach (self::getServiceConditionals($v) as $s) {
971+
if (!$this->has($s)) {
972+
continue 2;
973+
}
974+
}
975+
976+
yield $k => $this->resolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($v)));
977+
}
978+
});
964979
} elseif ($value instanceof Reference) {
965980
$value = $this->get((string) $value, $value->getInvalidBehavior());
966981
} elseif ($value instanceof Definition) {

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.