composer package updates
[openemr.git] / vendor / symfony / dependency-injection / Compiler / CheckReferenceValidityPass.php
blob71cb41d6697ffe6d76b4689359e720e591b47f26
1 <?php
3 /*
4 * This file is part of the Symfony package.
6 * (c) Fabien Potencier <fabien@symfony.com>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Symfony\Component\DependencyInjection\Compiler;
14 use Symfony\Component\DependencyInjection\Definition;
15 use Symfony\Component\DependencyInjection\ContainerInterface;
16 use Symfony\Component\DependencyInjection\Reference;
17 use Symfony\Component\DependencyInjection\ContainerBuilder;
18 use Symfony\Component\DependencyInjection\Exception\RuntimeException;
19 use Symfony\Component\DependencyInjection\Exception\ScopeCrossingInjectionException;
20 use Symfony\Component\DependencyInjection\Exception\ScopeWideningInjectionException;
22 /**
23 * Checks the validity of references.
25 * The following checks are performed by this pass:
26 * - target definitions are not abstract
27 * - target definitions are of equal or wider scope
28 * - target definitions are in the same scope hierarchy
30 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
32 class CheckReferenceValidityPass implements CompilerPassInterface
34 private $container;
35 private $currentId;
36 private $currentScope;
37 private $currentScopeAncestors;
38 private $currentScopeChildren;
40 /**
41 * Processes the ContainerBuilder to validate References.
43 public function process(ContainerBuilder $container)
45 $this->container = $container;
47 $children = $this->container->getScopeChildren(false);
48 $ancestors = array();
50 $scopes = $this->container->getScopes(false);
51 foreach ($scopes as $name => $parent) {
52 $ancestors[$name] = array($parent);
54 while (isset($scopes[$parent])) {
55 $ancestors[$name][] = $parent = $scopes[$parent];
59 foreach ($container->getDefinitions() as $id => $definition) {
60 if ($definition->isSynthetic() || $definition->isAbstract()) {
61 continue;
64 $this->currentId = $id;
65 $this->currentScope = $scope = $definition->getScope(false);
67 if (ContainerInterface::SCOPE_CONTAINER === $scope) {
68 $this->currentScopeChildren = array_keys($scopes);
69 $this->currentScopeAncestors = array();
70 } elseif (ContainerInterface::SCOPE_PROTOTYPE !== $scope) {
71 $this->currentScopeChildren = isset($children[$scope]) ? $children[$scope] : array();
72 $this->currentScopeAncestors = isset($ancestors[$scope]) ? $ancestors[$scope] : array();
75 $this->validateReferences($definition->getArguments());
76 $this->validateReferences($definition->getMethodCalls());
77 $this->validateReferences($definition->getProperties());
81 /**
82 * Validates an array of References.
84 * @param array $arguments An array of Reference objects
86 * @throws RuntimeException when there is a reference to an abstract definition
88 private function validateReferences(array $arguments)
90 foreach ($arguments as $argument) {
91 if (is_array($argument)) {
92 $this->validateReferences($argument);
93 } elseif ($argument instanceof Reference) {
94 $targetDefinition = $this->getDefinition((string) $argument);
96 if (null !== $targetDefinition && $targetDefinition->isAbstract()) {
97 throw new RuntimeException(sprintf(
98 'The definition "%s" has a reference to an abstract definition "%s". '
99 .'Abstract definitions cannot be the target of references.',
100 $this->currentId,
101 $argument
105 $this->validateScope($argument, $targetDefinition);
111 * Validates the scope of a single Reference.
113 * @throws ScopeWideningInjectionException when the definition references a service of a narrower scope
114 * @throws ScopeCrossingInjectionException when the definition references a service of another scope hierarchy
116 private function validateScope(Reference $reference, Definition $definition = null)
118 if (ContainerInterface::SCOPE_PROTOTYPE === $this->currentScope) {
119 return;
122 if (!$reference->isStrict(false)) {
123 return;
126 if (null === $definition) {
127 return;
130 if ($this->currentScope === $scope = $definition->getScope(false)) {
131 return;
134 $id = (string) $reference;
136 if (in_array($scope, $this->currentScopeChildren, true)) {
137 throw new ScopeWideningInjectionException($this->currentId, $this->currentScope, $id, $scope);
140 if (!in_array($scope, $this->currentScopeAncestors, true)) {
141 throw new ScopeCrossingInjectionException($this->currentId, $this->currentScope, $id, $scope);
146 * Returns the Definition given an id.
148 * @param string $id Definition identifier
150 * @return Definition
152 private function getDefinition($id)
154 if (!$this->container->hasDefinition($id)) {
155 return;
158 return $this->container->getDefinition($id);