024523e15585c709258124051377edc7850efb80
[yaffs-website] / vendor / symfony / dependency-injection / Compiler / ResolveBindingsPass.php
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\Compiler;
13
14 use Symfony\Component\DependencyInjection\Argument\BoundArgument;
15 use Symfony\Component\DependencyInjection\ContainerBuilder;
16 use Symfony\Component\DependencyInjection\Definition;
17 use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
18 use Symfony\Component\DependencyInjection\Exception\RuntimeException;
19 use Symfony\Component\DependencyInjection\LazyProxy\ProxyHelper;
20 use Symfony\Component\DependencyInjection\TypedReference;
21 use Symfony\Component\DependencyInjection\Reference;
22
23 /**
24  * @author Guilhem Niot <guilhem.niot@gmail.com>
25  */
26 class ResolveBindingsPass extends AbstractRecursivePass
27 {
28     private $usedBindings = array();
29     private $unusedBindings = array();
30
31     /**
32      * {@inheritdoc}
33      */
34     public function process(ContainerBuilder $container)
35     {
36         try {
37             parent::process($container);
38
39             foreach ($this->unusedBindings as list($key, $serviceId)) {
40                 throw new InvalidArgumentException(sprintf('Unused binding "%s" in service "%s".', $key, $serviceId));
41             }
42         } finally {
43             $this->usedBindings = array();
44             $this->unusedBindings = array();
45         }
46     }
47
48     /**
49      * {@inheritdoc}
50      */
51     protected function processValue($value, $isRoot = false)
52     {
53         if ($value instanceof TypedReference && $value->getType() === $this->container->normalizeId($value)) {
54             // Already checked
55             $bindings = $this->container->getDefinition($this->currentId)->getBindings();
56
57             if (isset($bindings[$value->getType()])) {
58                 return $this->getBindingValue($bindings[$value->getType()]);
59             }
60
61             return parent::processValue($value, $isRoot);
62         }
63
64         if (!$value instanceof Definition || !$bindings = $value->getBindings()) {
65             return parent::processValue($value, $isRoot);
66         }
67
68         foreach ($bindings as $key => $binding) {
69             list($bindingValue, $bindingId, $used) = $binding->getValues();
70             if ($used) {
71                 $this->usedBindings[$bindingId] = true;
72                 unset($this->unusedBindings[$bindingId]);
73             } elseif (!isset($this->usedBindings[$bindingId])) {
74                 $this->unusedBindings[$bindingId] = array($key, $this->currentId);
75             }
76
77             if (isset($key[0]) && '$' === $key[0]) {
78                 continue;
79             }
80
81             if (null !== $bindingValue && !$bindingValue instanceof Reference && !$bindingValue instanceof Definition) {
82                 throw new InvalidArgumentException(sprintf('Invalid value for binding key "%s" for service "%s": expected null, an instance of %s or an instance of %s, %s given.', $key, $this->currentId, Reference::class, Definition::class, gettype($bindingValue)));
83             }
84         }
85
86         if ($value->isAbstract()) {
87             return parent::processValue($value, $isRoot);
88         }
89
90         $calls = $value->getMethodCalls();
91
92         try {
93             if ($constructor = $this->getConstructor($value, false)) {
94                 $calls[] = array($constructor, $value->getArguments());
95             }
96         } catch (RuntimeException $e) {
97             $this->container->getDefinition($this->currentId)->addError($e->getMessage());
98
99             return parent::processValue($value, $isRoot);
100         }
101
102         foreach ($calls as $i => $call) {
103             list($method, $arguments) = $call;
104
105             if ($method instanceof \ReflectionFunctionAbstract) {
106                 $reflectionMethod = $method;
107             } else {
108                 $reflectionMethod = $this->getReflectionMethod($value, $method);
109             }
110
111             foreach ($reflectionMethod->getParameters() as $key => $parameter) {
112                 if (array_key_exists($key, $arguments) && '' !== $arguments[$key]) {
113                     continue;
114                 }
115
116                 if (array_key_exists('$'.$parameter->name, $bindings)) {
117                     $arguments[$key] = $this->getBindingValue($bindings['$'.$parameter->name]);
118
119                     continue;
120                 }
121
122                 $typeHint = ProxyHelper::getTypeHint($reflectionMethod, $parameter, true);
123
124                 if (!isset($bindings[$typeHint])) {
125                     continue;
126                 }
127
128                 $arguments[$key] = $this->getBindingValue($bindings[$typeHint]);
129             }
130
131             if ($arguments !== $call[1]) {
132                 ksort($arguments);
133                 $calls[$i][1] = $arguments;
134             }
135         }
136
137         if ($constructor) {
138             list(, $arguments) = array_pop($calls);
139
140             if ($arguments !== $value->getArguments()) {
141                 $value->setArguments($arguments);
142             }
143         }
144
145         if ($calls !== $value->getMethodCalls()) {
146             $value->setMethodCalls($calls);
147         }
148
149         return parent::processValue($value, $isRoot);
150     }
151
152     private function getBindingValue(BoundArgument $binding)
153     {
154         list($bindingValue, $bindingId) = $binding->getValues();
155
156         $this->usedBindings[$bindingId] = true;
157         unset($this->unusedBindings[$bindingId]);
158
159         return $bindingValue;
160     }
161 }