Skip to content

Commit f012c9a

Browse files
[DI] Add ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE
1 parent 61da487 commit f012c9a

27 files changed

+745
-16
lines changed

src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,16 @@ private function doProcessValue($value, $isRoot = false)
8686
if ($ref = $this->getAutowiredReference($value)) {
8787
return $ref;
8888
}
89-
$this->container->log($this, $this->createTypeNotFoundMessage($value, 'it'));
89+
$message = $this->createTypeNotFoundMessage($value, 'it');
90+
91+
if (ContainerBuilder::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE === $value->getInvalidBehavior()) {
92+
// since the error message varies by referenced id and $this->currentId, so should the id of the dummy errored definition
93+
$this->container->register($id = sprintf('_errored.%s.%s', $this->currentId, (string) $value), $value->getType())
94+
->addError($message);
95+
96+
return new TypedReference($id, $value->getType(), $value->getInvalidBehavior());
97+
}
98+
$this->container->log($this, $message);
9099
}
91100
$value = parent::processValue($value, $isRoot);
92101

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ protected function processValue($value, $isRoot = false)
2828
if (!$value instanceof Reference) {
2929
return parent::processValue($value, $isRoot);
3030
}
31-
if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE === $value->getInvalidBehavior() && !$this->container->has($id = (string) $value)) {
31+
if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE >= $value->getInvalidBehavior() && !$this->container->has($id = (string) $value)) {
3232
throw new ServiceNotFoundException($id, $this->currentId);
3333
}
3434
if (ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $value->getInvalidBehavior() && $this->container->has($id = (string) $value) && !$this->container->findDefinition($id)->isShared()) {

src/Symfony/Component/DependencyInjection/Compiler/DefinitionErrorExceptionPass.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@
1111

1212
namespace Symfony\Component\DependencyInjection\Compiler;
1313

14+
use Symfony\Component\DependencyInjection\ContainerInterface;
1415
use Symfony\Component\DependencyInjection\Definition;
1516
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
17+
use Symfony\Component\DependencyInjection\Reference;
1618

1719
/**
1820
* Throws an exception for any Definitions that have errors and still exist.
@@ -30,6 +32,21 @@ protected function processValue($value, $isRoot = false)
3032
return parent::processValue($value, $isRoot);
3133
}
3234

35+
if ($isRoot && !$value->isPublic()) {
36+
$graph = $this->container->getCompiler()->getServiceReferenceGraph();
37+
$runtimeException = false;
38+
foreach ($graph->getNode($this->currentId)->getInEdges() as $edge) {
39+
if (!$edge->getValue() instanceof Reference || ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE !== $edge->getValue()->getInvalidBehavior()) {
40+
$runtimeException = false;
41+
break;
42+
}
43+
$runtimeException = true;
44+
}
45+
if ($runtimeException) {
46+
return parent::processValue($value, $isRoot);
47+
}
48+
}
49+
3350
// only show the first error so the user can focus on it
3451
$errors = $value->getErrors();
3552
$message = reset($errors);

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ private function isInlineableDefinition($id, Definition $definition, ServiceRefe
9292
return true;
9393
}
9494

95-
if ($definition->isDeprecated() || $definition->isPublic() || $definition->isLazy()) {
95+
if ($definition->isDeprecated() || $definition->isPublic() || $definition->isLazy() || $definition->getErrors()) {
9696
return false;
9797
}
9898

src/Symfony/Component/DependencyInjection/Compiler/ResolveChildDefinitionsPass.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,10 @@ private function doResolveDefinition(ChildDefinition $definition)
163163
$def->setMethodCalls(array_merge($def->getMethodCalls(), $calls));
164164
}
165165

166+
foreach (array_merge($parentDef->getErrors(), $definition->getErrors()) as $v) {
167+
$def->addError($v);
168+
}
169+
166170
// these attributes are always taken from the child
167171
$def->setAbstract($definition->isAbstract());
168172
$def->setTags($definition->getTags());

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
1616
use Symfony\Component\DependencyInjection\ContainerInterface;
1717
use Symfony\Component\DependencyInjection\Definition;
18+
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
1819
use Symfony\Component\DependencyInjection\Reference;
20+
use Symfony\Component\DependencyInjection\TypedReference;
1921
use Symfony\Component\DependencyInjection\ContainerBuilder;
2022
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
2123

@@ -29,6 +31,7 @@ class ResolveInvalidReferencesPass implements CompilerPassInterface
2931
{
3032
private $container;
3133
private $signalingException;
34+
private $currentId;
3235

3336
/**
3437
* Process the ContainerBuilder to resolve invalid references.
@@ -67,6 +70,9 @@ private function processValue($value, $rootLevel = 0, $level = 0)
6770
$i = 0;
6871

6972
foreach ($value as $k => $v) {
73+
if (!$rootLevel) {
74+
$this->currentId = $k;
75+
}
7076
try {
7177
if (false !== $i && $k !== $i++) {
7278
$i = false;
@@ -90,11 +96,21 @@ private function processValue($value, $rootLevel = 0, $level = 0)
9096
$value = array_values($value);
9197
}
9298
} elseif ($value instanceof Reference) {
93-
if ($this->container->has($value)) {
99+
if ($this->container->has($id = (string) $value)) {
94100
return $value;
95101
}
96102
$invalidBehavior = $value->getInvalidBehavior();
97103

104+
if (ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE === $invalidBehavior && $value instanceof TypedReference && !$this->container->has($id)) {
105+
$e = new ServiceNotFoundException($id, $this->currentId);
106+
107+
// since the error message varies by $id and $this->currentId, so should the id of the dummy errored definition
108+
$this->container->register($id = sprintf('_errored.%s.%s', $this->currentId, $id), $value->getType())
109+
->addError($e->getMessage());
110+
111+
return new TypedReference($id, $value->getType(), $value->getInvalidBehavior());
112+
}
113+
98114
// resolve invalid behavior
99115
if (ContainerInterface::NULL_ON_INVALID_REFERENCE === $invalidBehavior) {
100116
$value = null;

src/Symfony/Component/DependencyInjection/ContainerBuilder.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,7 @@ public function has($id)
529529
*/
530530
public function get($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE)
531531
{
532-
if ($this->isCompiled() && isset($this->removedIds[$id = (string) $id]) && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE === $invalidBehavior) {
532+
if ($this->isCompiled() && isset($this->removedIds[$id = (string) $id]) && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE >= $invalidBehavior) {
533533
return parent::get($id);
534534
}
535535

@@ -555,13 +555,17 @@ private function doGet($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_
555555
try {
556556
$definition = $this->getDefinition($id);
557557
} catch (ServiceNotFoundException $e) {
558-
if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) {
558+
if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE < $invalidBehavior) {
559559
return;
560560
}
561561

562562
throw $e;
563563
}
564564

565+
if ($e = $definition->getErrors()) {
566+
throw new RuntimeException(reset($e));
567+
}
568+
565569
$loading = isset($this->alreadyLoading[$id]) ? 'loading' : 'alreadyLoading';
566570
$this->{$loading}[$id] = true;
567571

src/Symfony/Component/DependencyInjection/ContainerInterface.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
*/
2525
interface ContainerInterface extends PsrContainerInterface
2626
{
27+
const RUNTIME_EXCEPTION_ON_INVALID_REFERENCE = 0;
2728
const EXCEPTION_ON_INVALID_REFERENCE = 1;
2829
const NULL_ON_INVALID_REFERENCE = 2;
2930
const IGNORE_ON_INVALID_REFERENCE = 3;

src/Symfony/Component/DependencyInjection/Definition.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -873,10 +873,14 @@ public function setBindings(array $bindings)
873873
* Add an error that occurred when building this Definition.
874874
*
875875
* @param string $error
876+
*
877+
* @return $this
876878
*/
877879
public function addError($error)
878880
{
879881
$this->errors[] = $error;
882+
883+
return $this;
880884
}
881885

882886
/**

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

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ public function dump(array $options = array())
187187
<?php
188188
189189
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
190+
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
190191
191192
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
192193
@@ -320,7 +321,7 @@ private function addServiceLocalTempVariables(string $cId, Definition $definitio
320321
$name = $this->getNextVariableName();
321322
$this->referenceVariables[$id] = new Variable($name);
322323

323-
$reference = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE === $behavior[$id] ? new Reference($id, $behavior[$id]) : null;
324+
$reference = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE >= $behavior[$id] ? new Reference($id, $behavior[$id]) : null;
324325
$code .= sprintf(" \$%s = %s;\n", $name, $this->getServiceCall($id, $reference));
325326
}
326327

@@ -552,7 +553,7 @@ private function isTrivialInstance(Definition $definition): bool
552553
if ($definition->isSynthetic() || $definition->getFile() || $definition->getMethodCalls() || $definition->getProperties() || $definition->getConfigurator()) {
553554
return false;
554555
}
555-
if ($definition->isDeprecated() || $definition->isLazy() || $definition->getFactory() || 3 < count($definition->getArguments())) {
556+
if ($definition->isDeprecated() || $definition->isLazy() || $definition->getFactory() || 3 < count($definition->getArguments()) || $definition->getErrors()) {
556557
return false;
557558
}
558559

@@ -738,6 +739,12 @@ protected function {$methodName}($lazyInitialization)
738739
EOF;
739740
}
740741

742+
if ($e = $definition->getErrors()) {
743+
$e = sprintf("throw new RuntimeException(%s);\n", $this->export(reset($e)));
744+
745+
return $asFile ? substr($code, 8).$e : $code.' '.$e." }\n";
746+
}
747+
741748
$inlinedDefinitions = $this->getDefinitionsFromArguments(array($definition));
742749
$constructorDefinitions = $this->getDefinitionsFromArguments(array($definition->getArguments(), $definition->getFactory()));
743750
$otherDefinitions = new \SplObjectStorage();
@@ -1470,7 +1477,7 @@ private function dumpValue($value, bool $interpolate = true): string
14701477

14711478
$returnedType = '';
14721479
if ($value instanceof TypedReference) {
1473-
$returnedType = sprintf(': %s\%s', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE === $value->getInvalidBehavior() ? '' : '?', $value->getType());
1480+
$returnedType = sprintf(': %s\%s', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE >= $value->getInvalidBehavior() ? '' : '?', $value->getType());
14741481
}
14751482

14761483
$code = sprintf('return %s;', $code);
@@ -1675,7 +1682,7 @@ private function getServiceCall(string $id, Reference $reference = null): string
16751682
if (null !== $reference && ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $reference->getInvalidBehavior()) {
16761683
return 'null';
16771684
}
1678-
if (null !== $reference && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $reference->getInvalidBehavior()) {
1685+
if (null !== $reference && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE < $reference->getInvalidBehavior()) {
16791686
$code = sprintf('$this->get(\'%s\', /* ContainerInterface::NULL_ON_INVALID_REFERENCE */ %d)', $id, ContainerInterface::NULL_ON_INVALID_REFERENCE);
16801687
} else {
16811688
$code = sprintf('$this->get(\'%s\')', $id);

0 commit comments

Comments
 (0)