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 fa97a16

Browse filesBrowse files
[DI] Add ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE
1 parent b9fc357 commit fa97a16
Copy full SHA for fa97a16

25 files changed

+431
-53
lines changed

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/AnalyzeServiceReferencesPass.php
+3-1Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\DependencyInjection\Compiler;
1313

1414
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
15+
use Symfony\Component\DependencyInjection\ContainerInterface;
1516
use Symfony\Component\DependencyInjection\Definition;
1617
use Symfony\Component\DependencyInjection\ExpressionLanguage;
1718
use Symfony\Component\DependencyInjection\Reference;
@@ -96,7 +97,8 @@ protected function processValue($value, $isRoot = false)
9697
$this->getDefinitionId((string) $value),
9798
$targetDefinition,
9899
$value,
99-
$this->lazy || ($targetDefinition && $targetDefinition->isLazy())
100+
$this->lazy || ($targetDefinition && $targetDefinition->isLazy()),
101+
ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $value->getInvalidBehavior()
100102
);
101103

102104
return $value;

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/CheckExceptionOnInvalidReferenceBehaviorPass.php
+10-7Lines changed: 10 additions & 7 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\Exception\InvalidArgumentException;
1415
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
1516
use Symfony\Component\DependencyInjection\ContainerInterface;
1617
use Symfony\Component\DependencyInjection\Reference;
@@ -24,14 +25,16 @@ class CheckExceptionOnInvalidReferenceBehaviorPass extends AbstractRecursivePass
2425
{
2526
protected function processValue($value, $isRoot = false)
2627
{
27-
if ($value instanceof Reference && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE === $value->getInvalidBehavior()) {
28-
$destId = (string) $value;
29-
30-
if (!$this->container->has($destId)) {
31-
throw new ServiceNotFoundException($destId, $this->currentId);
32-
}
28+
if (!$value instanceof Reference) {
29+
return parent::processValue($value, $isRoot);
30+
}
31+
if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE === $value->getInvalidBehavior() && !$this->container->has($id = (string) $value)) {
32+
throw new ServiceNotFoundException($id, $this->currentId);
33+
}
34+
if (ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $value->getInvalidBehavior() && $this->container->has($id = (string) $value) && !$this->container->findDefinition($id)->isShared()) {
35+
throw new InvalidArgumentException(sprintf('Invalid ignore-on-uninitialized reference found in service "%s": target service "%s" is not shared.', $this->currentId, $id));
3336
}
3437

35-
return parent::processValue($value, $isRoot);
38+
return $value;
3639
}
3740
}

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\DependencyInjection\Compiler;
1313

1414
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
15+
use Symfony\Component\DependencyInjection\ContainerInterface;
1516
use Symfony\Component\DependencyInjection\Definition;
1617
use Symfony\Component\DependencyInjection\Reference;
1718

@@ -96,6 +97,9 @@ private function isInlineableDefinition($id, Definition $definition, ServiceRefe
9697

9798
$ids = array();
9899
foreach ($graph->getNode($id)->getInEdges() as $edge) {
100+
if ($edge->isWeak()) {
101+
return false;
102+
}
99103
$ids[] = $edge->getSourceNode()->getId();
100104
}
101105

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ protected function processValue($value, $isRoot = false)
7474
if ($optionalBehavior = '?' === $type[0]) {
7575
$type = substr($type, 1);
7676
$optionalBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE;
77+
} elseif ($optionalBehavior = '!' === $type[0]) {
78+
$type = substr($type, 1);
79+
$optionalBehavior = ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE;
7780
}
7881
if (is_int($key)) {
7982
$key = $type;

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/RemoveUnusedDefinitionsPass.php
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ public function process(ContainerBuilder $container)
5050
$referencingAliases = array();
5151
$sourceIds = array();
5252
foreach ($edges as $edge) {
53+
if ($edge->isWeak()) {
54+
continue;
55+
}
5356
$node = $edge->getSourceNode();
5457
$sourceIds[] = $node->getId();
5558

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/ServiceReferenceGraph.php
+8-13Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
* it themselves which improves performance quite a lot.
2121
*
2222
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
23+
*
24+
* @final since version 3.4
2325
*/
2426
class ServiceReferenceGraph
2527
{
@@ -85,23 +87,16 @@ public function clear()
8587
* @param string $destValue
8688
* @param string $reference
8789
* @param bool $lazy
90+
* @param bool $weak
8891
*/
89-
public function connect($sourceId, $sourceValue, $destId, $destValue = null, $reference = null/*, bool $lazy = false*/)
92+
public function connect($sourceId, $sourceValue, $destId, $destValue = null, $reference = null/*, bool $lazy = false, bool $weak = false*/)
9093
{
91-
if (func_num_args() >= 6) {
92-
$lazy = func_get_arg(5);
93-
} else {
94-
if (__CLASS__ !== get_class($this)) {
95-
$r = new \ReflectionMethod($this, __FUNCTION__);
96-
if (__CLASS__ !== $r->getDeclaringClass()->getName()) {
97-
@trigger_error(sprintf('Method %s() will have a 6th `bool $lazy = false` argument in version 4.0. Not defining it is deprecated since 3.3.', __METHOD__), E_USER_DEPRECATED);
98-
}
99-
}
100-
$lazy = false;
101-
}
94+
$lazy = func_num_args() >= 6 ? func_get_arg(5) : false;
95+
$weak = func_num_args() >= 7 ? func_get_arg(6) : false;
96+
10297
$sourceNode = $this->createNode($sourceId, $sourceValue);
10398
$destNode = $this->createNode($destId, $destValue);
104-
$edge = new ServiceReferenceGraphEdge($sourceNode, $destNode, $reference, $lazy);
99+
$edge = new ServiceReferenceGraphEdge($sourceNode, $destNode, $reference, $lazy, $weak);
105100

106101
$sourceNode->addOutEdge($edge);
107102
$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
@@ -24,19 +24,22 @@ class ServiceReferenceGraphEdge
2424
private $destNode;
2525
private $value;
2626
private $lazy;
27+
private $weak;
2728

2829
/**
2930
* @param ServiceReferenceGraphNode $sourceNode
3031
* @param ServiceReferenceGraphNode $destNode
3132
* @param string $value
3233
* @param bool $lazy
34+
* @param bool $weak
3335
*/
34-
public function __construct(ServiceReferenceGraphNode $sourceNode, ServiceReferenceGraphNode $destNode, $value = null, $lazy = false)
36+
public function __construct(ServiceReferenceGraphNode $sourceNode, ServiceReferenceGraphNode $destNode, $value = null, $lazy = false, $weak = false)
3537
{
3638
$this->sourceNode = $sourceNode;
3739
$this->destNode = $destNode;
3840
$this->value = $value;
3941
$this->lazy = $lazy;
42+
$this->weak = $weak;
4043
}
4144

4245
/**
@@ -78,4 +81,14 @@ public function isLazy()
7881
{
7982
return $this->lazy;
8083
}
84+
85+
/**
86+
* Returns true if the edge is weak, meaning it shouldn't prevent removing the target service.
87+
*
88+
* @return bool
89+
*/
90+
public function isWeak()
91+
{
92+
return $this->weak;
93+
}
8194
}

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Container.php
+6-17Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,26 +23,15 @@
2323
* Container is a dependency injection container.
2424
*
2525
* It gives access to object instances (services).
26-
*
2726
* Services and parameters are simple key/pair stores.
28-
*
29-
* Parameter and service keys are case insensitive.
30-
*
31-
* A service can also be defined by creating a method named
32-
* getXXXService(), where XXX is the camelized version of the id:
33-
*
34-
* <ul>
35-
* <li>request -> getRequestService()</li>
36-
* <li>mysql_session_storage -> getMysqlSessionStorageService()</li>
37-
* <li>symfony.mysql_session_storage -> getSymfony_MysqlSessionStorageService()</li>
38-
* </ul>
39-
*
40-
* The container can have three possible behaviors when a service does not exist:
27+
* The container can have four possible behaviors when a service
28+
* does not exist (or is not initialized for the last case):
4129
*
4230
* * EXCEPTION_ON_INVALID_REFERENCE: Throws an exception (the default)
4331
* * NULL_ON_INVALID_REFERENCE: Returns null
4432
* * IGNORE_ON_INVALID_REFERENCE: Ignores the wrapping command asking for the reference
4533
* (for instance, ignore a setter if the service does not exist)
34+
* * IGNORE_ON_UNINITIALIZED_REFERENCE: Ignores/returns null for uninitialized services or invalid references
4635
*
4736
* @author Fabien Potencier <fabien@symfony.com>
4837
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
@@ -304,9 +293,9 @@ public function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE
304293

305294
try {
306295
if (isset($this->fileMap[$id])) {
307-
return $this->load($this->fileMap[$id]);
296+
return self::IGNORE_ON_UNINITIALIZED_REFERENCE === $invalidBehavior ? null : $this->load($this->fileMap[$id]);
308297
} elseif (isset($this->methodMap[$id])) {
309-
return $this->{$this->methodMap[$id]}();
298+
return self::IGNORE_ON_UNINITIALIZED_REFERENCE === $invalidBehavior ? null : $this->{$this->methodMap[$id]}();
310299
} elseif (--$i && $id !== $normalizedId = $this->normalizeId($id)) {
311300
$id = $normalizedId;
312301
continue;
@@ -315,7 +304,7 @@ public function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE
315304
// and only when the dumper has not generated the method map (otherwise the method map is considered to be fully populated by the dumper)
316305
@trigger_error('Generating a dumped container without populating the method map is deprecated since 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map.', E_USER_DEPRECATED);
317306

318-
return $this->{$method}();
307+
return self::IGNORE_ON_UNINITIALIZED_REFERENCE === $invalidBehavior ? null : $this->{$method}();
319308
}
320309

321310
break;

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/ContainerBuilder.php
+45-3Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,9 @@ public function get($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INV
565565
{
566566
$id = $this->normalizeId($id);
567567

568+
if (ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $invalidBehavior) {
569+
return parent::get($id, $invalidBehavior);
570+
}
568571
if ($service = parent::get($id, ContainerInterface::NULL_ON_INVALID_REFERENCE)) {
569572
return $service;
570573
}
@@ -1160,6 +1163,11 @@ public function resolveServices($value)
11601163
continue 2;
11611164
}
11621165
}
1166+
foreach (self::getInitializedConditionals($v) as $s) {
1167+
if (!$this->get($s, ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE)) {
1168+
continue 2;
1169+
}
1170+
}
11631171

11641172
yield $k => $this->resolveServices($v);
11651173
}
@@ -1171,6 +1179,11 @@ public function resolveServices($value)
11711179
continue 2;
11721180
}
11731181
}
1182+
foreach (self::getInitializedConditionals($v) as $s) {
1183+
if (!$this->get($s, ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE)) {
1184+
continue 2;
1185+
}
1186+
}
11741187

11751188
++$count;
11761189
}
@@ -1397,6 +1410,8 @@ public function log(CompilerPassInterface $pass, $message)
13971410
* @param mixed $value An array of conditionals to return
13981411
*
13991412
* @return array An array of Service conditionals
1413+
*
1414+
* @internal since version 3.4
14001415
*/
14011416
public static function getServiceConditionals($value)
14021417
{
@@ -1413,6 +1428,30 @@ public static function getServiceConditionals($value)
14131428
return $services;
14141429
}
14151430

1431+
/**
1432+
* Returns the initialized conditionals.
1433+
*
1434+
* @param mixed $value An array of conditionals to return
1435+
*
1436+
* @return array An array of uninitialized conditionals
1437+
*
1438+
* @internal
1439+
*/
1440+
public static function getInitializedConditionals($value)
1441+
{
1442+
$services = array();
1443+
1444+
if (is_array($value)) {
1445+
foreach ($value as $v) {
1446+
$services = array_unique(array_merge($services, self::getInitializedConditionals($v)));
1447+
}
1448+
} elseif ($value instanceof Reference && $value->getInvalidBehavior() === ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE) {
1449+
$services[] = (string) $value;
1450+
}
1451+
1452+
return $services;
1453+
}
1454+
14161455
/**
14171456
* Computes a reasonably unique hash of a value.
14181457
*
@@ -1465,13 +1504,16 @@ private function getProxyInstantiator()
14651504

14661505
private function callMethod($service, $call)
14671506
{
1468-
$services = self::getServiceConditionals($call[1]);
1469-
1470-
foreach ($services as $s) {
1507+
foreach (self::getServiceConditionals($call[1]) as $s) {
14711508
if (!$this->has($s)) {
14721509
return;
14731510
}
14741511
}
1512+
foreach (self::getInitializedConditionals($call[1]) as $s) {
1513+
if (!$this->get($s, ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE)) {
1514+
return;
1515+
}
1516+
}
14751517

14761518
call_user_func_array(array($service, $call[0]), $this->resolveServices($this->getParameterBag()->unescapeValue($this->getParameterBag()->resolveValue($call[1]))));
14771519
}

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/ContainerInterface.php
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ interface ContainerInterface extends PsrContainerInterface
2727
const EXCEPTION_ON_INVALID_REFERENCE = 1;
2828
const NULL_ON_INVALID_REFERENCE = 2;
2929
const IGNORE_ON_INVALID_REFERENCE = 3;
30+
const IGNORE_ON_UNINITIALIZED_REFERENCE = 4;
3031

3132
/**
3233
* Sets a service.

‎src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
+13-9Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ private function addServiceLocalTempVariables($cId, Definition $definition, arra
277277
if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE === $behavior[$id]) {
278278
$code .= sprintf($template, $name, $this->getServiceCall($id));
279279
} else {
280-
$code .= sprintf($template, $name, $this->getServiceCall($id, new Reference($id, ContainerInterface::NULL_ON_INVALID_REFERENCE)));
280+
$code .= sprintf($template, $name, $this->getServiceCall($id, new Reference($id, $behavior[$id])));
281281
}
282282
}
283283
}
@@ -1295,12 +1295,14 @@ private function wrapServiceConditionals($value, $code)
12951295
*/
12961296
private function getServiceConditionals($value)
12971297
{
1298-
if (!$services = ContainerBuilder::getServiceConditionals($value)) {
1299-
return null;
1300-
}
1301-
13021298
$conditions = array();
1303-
foreach ($services as $service) {
1299+
foreach (ContainerBuilder::getInitializedConditionals($value) as $service) {
1300+
if (!$this->container->hasDefinition($service)) {
1301+
return 'false';
1302+
}
1303+
$conditions[] = sprintf("isset(\$this->services['%s'])", $service);
1304+
}
1305+
foreach (ContainerBuilder::getServiceConditionals($value) as $service) {
13041306
if ($this->container->hasDefinition($service) && !$this->container->getDefinition($service)->isPublic()) {
13051307
continue;
13061308
}
@@ -1335,8 +1337,8 @@ private function getServiceCallsFromArguments(array $arguments, array &$calls, a
13351337
}
13361338
if (!isset($behavior[$id])) {
13371339
$behavior[$id] = $argument->getInvalidBehavior();
1338-
} elseif (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $behavior[$id]) {
1339-
$behavior[$id] = $argument->getInvalidBehavior();
1340+
} else {
1341+
$behavior[$id] = min($behavior[$id], $argument->getInvalidBehavior());
13401342
}
13411343

13421344
++$calls[$id];
@@ -1665,7 +1667,9 @@ private function getServiceCall($id, Reference $reference = null)
16651667
return '$this';
16661668
}
16671669

1668-
if ($this->asFiles && $this->container->hasDefinition($id)) {
1670+
if (null !== $reference && ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $reference->getInvalidBehavior()) {
1671+
$code = 'null';
1672+
} elseif ($this->asFiles && $this->container->hasDefinition($id)) {
16691673
if ($this->container->getDefinition($id)->isShared()) {
16701674
$code = sprintf("\$this->load(__DIR__.'/%s.php')", $this->generateMethodName($id));
16711675
} else {

‎src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,8 @@ private function convertParameters(array $parameters, $type, \DOMElement $parent
309309
$element->setAttribute('on-invalid', 'null');
310310
} elseif ($behaviour == ContainerInterface::IGNORE_ON_INVALID_REFERENCE) {
311311
$element->setAttribute('on-invalid', 'ignore');
312+
} elseif ($behaviour == ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE) {
313+
$element->setAttribute('on-invalid', 'ignore_uninitialized');
312314
}
313315
} elseif ($value instanceof Definition) {
314316
$element->setAttribute('type', 'service');

‎src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php
+6-2Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -304,8 +304,12 @@ private function dumpValue($value)
304304
*/
305305
private function getServiceCall($id, Reference $reference = null)
306306
{
307-
if (null !== $reference && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $reference->getInvalidBehavior()) {
308-
return sprintf('@?%s', $id);
307+
if (null !== $reference) {
308+
switch ($reference->getInvalidBehavior()) {
309+
case ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE: break;
310+
case ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE: return sprintf('@!%s', $id);
311+
default: return sprintf('@?%s', $id);
312+
}
309313
}
310314

311315
return sprintf('@%s', $id);

0 commit comments

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