Skip to content

Commit 19f2e1e

Browse files
tgalopinnicolas-grekas
authored andcommitted
[DependencyInjection] Implement lazy collection type using generators
1 parent 813d44d commit 19f2e1e

Some content is hidden

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

42 files changed

+531
-14
lines changed

Argument/ArgumentInterface.php

Lines 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+
}

Argument/IteratorArgument.php

Lines 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+
}

Argument/RewindableGenerator.php

Lines 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+
}

Compiler/AnalyzeServiceReferencesPass.php

Lines 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());

Compiler/CheckCircularReferencesPass.php

Lines 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

Compiler/CheckExceptionOnInvalidReferenceBehaviorPass.php

Lines 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()) {

Compiler/CheckReferenceValidityPass.php

Lines 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

Compiler/InlineServiceDefinitionsPass.php

Lines 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;

Compiler/ReplaceAliasByActualDefinitionPass.php

Lines 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;

Compiler/ResolveDefinitionTemplatesPass.php

Lines 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);

0 commit comments

Comments
 (0)