Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8ee6428

Browse files
[DI] Add ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_DEFINITION
1 parent 07a2f6c commit 8ee6428

21 files changed

+679
-13
lines changed

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

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,15 @@ private function doProcessValue($value, $isRoot = false)
8888
if ($ref = $this->getAutowiredReference($value, $value->getRequiringClass() ? sprintf('for "%s" in "%s"', $value->getType(), $value->getRequiringClass()) : '')) {
8989
return $ref;
9090
}
91-
$this->container->log($this, $this->createTypeNotFoundMessage($value, 'it'));
91+
$message = $this->createTypeNotFoundMessage($value, 'it');
92+
93+
if (ContainerBuilder::RUNTIME_EXCEPTION_ON_INVALID_DEFINITION === $value->getInvalidBehavior()) {
94+
$this->container->register((string) $value, $value->getType())
95+
->addError($message);
96+
97+
return $value;
98+
}
99+
$this->container->log($this, $message);
92100
}
93101
$value = parent::processValue($value, $isRoot);
94102

@@ -376,7 +384,8 @@ private function createTypeNotFoundMessage(TypedReference $reference, $label)
376384
}
377385
}
378386

379-
$message = sprintf('Cannot autowire service "%s": %s %s', $this->currentId, $label, $message);
387+
$id = $reference->getRequiringClass() && $this->container->getDefinition($this->currentId)->hasTag('container.service_locator') ? sprintf('class "%s"', $reference->getRequiringClass()) : sprintf('service "%s"', $this->currentId);
388+
$message = sprintf('Cannot autowire %s: %s %s', $id, $label, $message);
380389

381390
if (null !== $this->lastFailure) {
382391
$message = $this->lastFailure."\n".$message;

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_DEFINITION !== $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/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_DEFINITION = 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);

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ private function getServiceCall(string $id, Reference $reference = null): string
266266
{
267267
if (null !== $reference) {
268268
switch ($reference->getInvalidBehavior()) {
269+
case ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_DEFINITION: break;
269270
case ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE: break;
270271
case ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE: return sprintf('@!%s', $id);
271272
default: return sprintf('@?%s', $id);

src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use Symfony\Component\DependencyInjection\Compiler\DecoratorServicePass;
2121
use Symfony\Component\DependencyInjection\Compiler\ResolveClassPass;
2222
use Symfony\Component\DependencyInjection\ContainerBuilder;
23+
use Symfony\Component\DependencyInjection\Definition;
2324
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
2425
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
2526
use Symfony\Component\DependencyInjection\Reference;
@@ -845,4 +846,18 @@ public function testDoNotAutowireDecoratorWhenSeveralArgumentOfTheType()
845846
(new DecoratorServicePass())->process($container);
846847
(new AutowirePass())->process($container);
847848
}
849+
850+
public function testErroredServiceLocator()
851+
{
852+
$container = new ContainerBuilder();
853+
$container->register('some_locator', 'stdClass')
854+
->addArgument(new TypedReference(MissingClass::class, MissingClass::class, __CLASS__, ContainerBuilder::RUNTIME_EXCEPTION_ON_INVALID_DEFINITION))
855+
->addTag('container.service_locator');
856+
857+
(new AutowirePass())->process($container);
858+
859+
$erroredDefinition = new Definition(MissingClass::class);
860+
861+
$this->assertEquals($erroredDefinition->addError('Cannot autowire class "Symfony\Component\DependencyInjection\Tests\Compiler\AutowirePassTest": it has type "Symfony\Component\DependencyInjection\Tests\Compiler\MissingClass" but this class was not found.'), $container->getDefinition(MissingClass::class));
862+
}
848863
}

src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1367,6 +1367,21 @@ public function testIdCanBeAnObjectAsLongAsItCanBeCastToString()
13671367
$container->removeAlias($aliasId);
13681368
$container->removeDefinition($id);
13691369
}
1370+
1371+
/**
1372+
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
1373+
* @expectedExceptionMessage Service "errored_definition" is broken.
1374+
*/
1375+
public function testErroredDefinition()
1376+
{
1377+
$container = new ContainerBuilder();
1378+
1379+
$container->register('errored_definition', 'stdClass')
1380+
->addError('Service "errored_definition" is broken.')
1381+
->setPublic(true);
1382+
1383+
$container->get('errored_definition');
1384+
}
13701385
}
13711386

13721387
class FooClass

src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -946,6 +946,23 @@ public function testParameterWithMixedCase()
946946
$this->assertSame('bar', $container->getParameter('Foo'));
947947
$this->assertSame('foo', $container->getParameter('BAR'));
948948
}
949+
950+
/**
951+
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
952+
* @expectedExceptionMessage Service "errored_definition" is broken.
953+
*/
954+
public function testErroredDefinition()
955+
{
956+
$container = include self::$fixturesPath.'/containers/container9.php';
957+
$container->setParameter('foo_bar', 'foo_bar');
958+
$container->compile();
959+
$dumper = new PhpDumper($container);
960+
eval('?>'.$dump = $dumper->dump(array('class' => 'Symfony_DI_PhpDumper_Errored_Definition')));
961+
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services_errored_definition.php', $dump);
962+
963+
$container = new \Symfony_DI_PhpDumper_Errored_Definition();
964+
$container->get('runtime_error');
965+
}
949966
}
950967

951968
class Rot13EnvVarProcessor implements EnvVarProcessorInterface

src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container9.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,4 +180,11 @@
180180
$container->setAlias('alias_for_foo', 'foo')->setPublic(true);
181181
$container->setAlias('alias_for_alias', 'alias_for_foo')->setPublic(true);
182182

183+
$container->register('runtime_error', 'stdClass')
184+
->addArgument(new Reference('errored_definition', ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_DEFINITION))
185+
->setPublic(true);
186+
187+
$container->register('errored_definition', 'stdClass')
188+
->addError('Service "errored_definition" is broken.');
189+
183190
return $container;

src/Symfony/Component/DependencyInjection/Tests/Fixtures/graphviz/services9.dot

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ digraph sc {
3434
node_BAR2 [label="BAR2\nstdClass\n", shape=record, fillcolor="#eeeeee", style="filled"];
3535
node_tagged_iterator_foo [label="tagged_iterator_foo\nBar\n", shape=record, fillcolor="#eeeeee", style="filled"];
3636
node_tagged_iterator [label="tagged_iterator\nBar\n", shape=record, fillcolor="#eeeeee", style="filled"];
37+
node_runtime_error [label="runtime_error\nstdClass\n", shape=record, fillcolor="#eeeeee", style="filled"];
38+
node_errored_definition [label="errored_definition\nstdClass\n", shape=record, fillcolor="#eeeeee", style="filled"];
3739
node_foo2 [label="foo2\n\n", shape=record, fillcolor="#ff9999", style="filled"];
3840
node_foo3 [label="foo3\n\n", shape=record, fillcolor="#ff9999", style="filled"];
3941
node_foobaz [label="foobaz\n\n", shape=record, fillcolor="#ff9999", style="filled"];
@@ -57,4 +59,5 @@ digraph sc {
5759
node_lazy_context_ignore_invalid_ref -> node_foo_baz [label="" style="filled" color="#9999ff"];
5860
node_lazy_context_ignore_invalid_ref -> node_invalid [label="" style="filled" color="#9999ff"];
5961
node_BAR -> node_bar [label="" style="dashed"];
62+
node_runtime_error -> node_errored_definition [label="" style="filled"];
6063
}

0 commit comments

Comments
 (0)