Mercurial > hg > isophonics-drupal-site
comparison core/lib/Drupal/Component/DependencyInjection/PhpArrayContainer.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children | 129ea1e6d783 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4c8ae668cc8c |
---|---|
1 <?php | |
2 | |
3 namespace Drupal\Component\DependencyInjection; | |
4 | |
5 use Symfony\Component\DependencyInjection\ContainerInterface; | |
6 use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; | |
7 use Symfony\Component\DependencyInjection\Exception\RuntimeException; | |
8 | |
9 /** | |
10 * Provides a container optimized for Drupal's needs. | |
11 * | |
12 * This container implementation is compatible with the default Symfony | |
13 * dependency injection container and similar to the Symfony ContainerBuilder | |
14 * class, but optimized for speed. | |
15 * | |
16 * It is based on a human-readable PHP array container definition with a | |
17 * structure very similar to the YAML container definition. | |
18 * | |
19 * @see \Drupal\Component\DependencyInjection\Container | |
20 * @see \Drupal\Component\DependencyInjection\Dumper\PhpArrayDumper | |
21 * @see \Drupal\Component\DependencyInjection\DependencySerializationTrait | |
22 * | |
23 * @ingroup container | |
24 */ | |
25 class PhpArrayContainer extends Container { | |
26 | |
27 /** | |
28 * {@inheritdoc} | |
29 */ | |
30 public function __construct(array $container_definition = []) { | |
31 if (isset($container_definition['machine_format']) && $container_definition['machine_format'] === TRUE) { | |
32 throw new InvalidArgumentException('The machine-optimized format is not supported by this class. Use a human-readable format instead, e.g. as produced by \Drupal\Component\DependencyInjection\Dumper\PhpArrayDumper.'); | |
33 } | |
34 | |
35 // Do not call the parent's constructor as it would bail on the | |
36 // machine-optimized format. | |
37 $this->aliases = isset($container_definition['aliases']) ? $container_definition['aliases'] : []; | |
38 $this->parameters = isset($container_definition['parameters']) ? $container_definition['parameters'] : []; | |
39 $this->serviceDefinitions = isset($container_definition['services']) ? $container_definition['services'] : []; | |
40 $this->frozen = isset($container_definition['frozen']) ? $container_definition['frozen'] : FALSE; | |
41 | |
42 // Register the service_container with itself. | |
43 $this->services['service_container'] = $this; | |
44 } | |
45 | |
46 /** | |
47 * {@inheritdoc} | |
48 */ | |
49 protected function createService(array $definition, $id) { | |
50 // This method is a verbatim copy of | |
51 // \Drupal\Component\DependencyInjection\Container::createService | |
52 // except for the following difference: | |
53 // - There are no instanceof checks on \stdClass, which are used in the | |
54 // parent class to avoid resolving services and parameters when it is | |
55 // known from dumping that there is nothing to resolve. | |
56 if (isset($definition['synthetic']) && $definition['synthetic'] === TRUE) { | |
57 throw new RuntimeException(sprintf('You have requested a synthetic service ("%s"). The service container does not know how to construct this service. The service will need to be set before it is first used.', $id)); | |
58 } | |
59 | |
60 $arguments = []; | |
61 if (isset($definition['arguments'])) { | |
62 $arguments = $this->resolveServicesAndParameters($definition['arguments']); | |
63 } | |
64 | |
65 if (isset($definition['file'])) { | |
66 $file = $this->frozen ? $definition['file'] : current($this->resolveServicesAndParameters([$definition['file']])); | |
67 require_once $file; | |
68 } | |
69 | |
70 if (isset($definition['factory'])) { | |
71 $factory = $definition['factory']; | |
72 if (is_array($factory)) { | |
73 $factory = $this->resolveServicesAndParameters([$factory[0], $factory[1]]); | |
74 } | |
75 elseif (!is_string($factory)) { | |
76 throw new RuntimeException(sprintf('Cannot create service "%s" because of invalid factory', $id)); | |
77 } | |
78 | |
79 $service = call_user_func_array($factory, $arguments); | |
80 } | |
81 else { | |
82 $class = $this->frozen ? $definition['class'] : current($this->resolveServicesAndParameters([$definition['class']])); | |
83 $length = isset($definition['arguments_count']) ? $definition['arguments_count'] : count($arguments); | |
84 | |
85 // Optimize class instantiation for services with up to 10 parameters as | |
86 // reflection is noticeably slow. | |
87 switch ($length) { | |
88 case 0: | |
89 $service = new $class(); | |
90 break; | |
91 | |
92 case 1: | |
93 $service = new $class($arguments[0]); | |
94 break; | |
95 | |
96 case 2: | |
97 $service = new $class($arguments[0], $arguments[1]); | |
98 break; | |
99 | |
100 case 3: | |
101 $service = new $class($arguments[0], $arguments[1], $arguments[2]); | |
102 break; | |
103 | |
104 case 4: | |
105 $service = new $class($arguments[0], $arguments[1], $arguments[2], $arguments[3]); | |
106 break; | |
107 | |
108 case 5: | |
109 $service = new $class($arguments[0], $arguments[1], $arguments[2], $arguments[3], $arguments[4]); | |
110 break; | |
111 | |
112 case 6: | |
113 $service = new $class($arguments[0], $arguments[1], $arguments[2], $arguments[3], $arguments[4], $arguments[5]); | |
114 break; | |
115 | |
116 case 7: | |
117 $service = new $class($arguments[0], $arguments[1], $arguments[2], $arguments[3], $arguments[4], $arguments[5], $arguments[6]); | |
118 break; | |
119 | |
120 case 8: | |
121 $service = new $class($arguments[0], $arguments[1], $arguments[2], $arguments[3], $arguments[4], $arguments[5], $arguments[6], $arguments[7]); | |
122 break; | |
123 | |
124 case 9: | |
125 $service = new $class($arguments[0], $arguments[1], $arguments[2], $arguments[3], $arguments[4], $arguments[5], $arguments[6], $arguments[7], $arguments[8]); | |
126 break; | |
127 | |
128 case 10: | |
129 $service = new $class($arguments[0], $arguments[1], $arguments[2], $arguments[3], $arguments[4], $arguments[5], $arguments[6], $arguments[7], $arguments[8], $arguments[9]); | |
130 break; | |
131 | |
132 default: | |
133 $r = new \ReflectionClass($class); | |
134 $service = $r->newInstanceArgs($arguments); | |
135 break; | |
136 } | |
137 } | |
138 | |
139 if (!isset($definition['shared']) || $definition['shared'] !== FALSE) { | |
140 $this->services[$id] = $service; | |
141 } | |
142 | |
143 if (isset($definition['calls'])) { | |
144 foreach ($definition['calls'] as $call) { | |
145 $method = $call[0]; | |
146 $arguments = []; | |
147 if (!empty($call[1])) { | |
148 $arguments = $call[1]; | |
149 $arguments = $this->resolveServicesAndParameters($arguments); | |
150 } | |
151 call_user_func_array([$service, $method], $arguments); | |
152 } | |
153 } | |
154 | |
155 if (isset($definition['properties'])) { | |
156 $definition['properties'] = $this->resolveServicesAndParameters($definition['properties']); | |
157 foreach ($definition['properties'] as $key => $value) { | |
158 $service->{$key} = $value; | |
159 } | |
160 } | |
161 | |
162 if (isset($definition['configurator'])) { | |
163 $callable = $definition['configurator']; | |
164 if (is_array($callable)) { | |
165 $callable = $this->resolveServicesAndParameters($callable); | |
166 } | |
167 | |
168 if (!is_callable($callable)) { | |
169 throw new InvalidArgumentException(sprintf('The configurator for class "%s" is not a callable.', get_class($service))); | |
170 } | |
171 | |
172 call_user_func($callable, $service); | |
173 } | |
174 | |
175 return $service; | |
176 } | |
177 | |
178 /** | |
179 * {@inheritdoc} | |
180 */ | |
181 protected function resolveServicesAndParameters($arguments) { | |
182 // This method is different from the parent method only for the following | |
183 // cases: | |
184 // - A service is denoted by '@service' and not by a \stdClass object. | |
185 // - A parameter is denoted by '%parameter%' and not by a \stdClass object. | |
186 // - The depth of the tree representing the arguments is not known in | |
187 // advance, so it needs to be fully traversed recursively. | |
188 foreach ($arguments as $key => $argument) { | |
189 if ($argument instanceof \stdClass) { | |
190 $type = $argument->type; | |
191 | |
192 // Private services are a special flavor: In case a private service is | |
193 // only used by one other service, the ContainerBuilder uses a | |
194 // Definition object as an argument, which does not have an ID set. | |
195 // Therefore the format uses a \stdClass object to store the definition | |
196 // and to be able to create the service on the fly. | |
197 // | |
198 // Note: When constructing a private service by hand, 'id' must be set. | |
199 // | |
200 // The PhpArrayDumper just uses the hash of the private service | |
201 // definition to generate a unique ID. | |
202 // | |
203 // @see \Drupal\Component\DependecyInjection\Dumper\OptimizedPhpArrayDumper::getPrivateServiceCall | |
204 if ($type == 'private_service') { | |
205 $id = $argument->id; | |
206 | |
207 // Check if the private service already exists - in case it is shared. | |
208 if (!empty($argument->shared) && isset($this->privateServices[$id])) { | |
209 $arguments[$key] = $this->privateServices[$id]; | |
210 continue; | |
211 } | |
212 | |
213 // Create a private service from a service definition. | |
214 $arguments[$key] = $this->createService($argument->value, $id); | |
215 if (!empty($argument->shared)) { | |
216 $this->privateServices[$id] = $arguments[$key]; | |
217 } | |
218 | |
219 continue; | |
220 } | |
221 | |
222 if ($type !== NULL) { | |
223 throw new InvalidArgumentException("Undefined type '$type' while resolving parameters and services."); | |
224 } | |
225 } | |
226 | |
227 if (is_array($argument)) { | |
228 $arguments[$key] = $this->resolveServicesAndParameters($argument); | |
229 continue; | |
230 } | |
231 | |
232 if (!is_string($argument)) { | |
233 continue; | |
234 } | |
235 | |
236 // Resolve parameters. | |
237 if ($argument[0] === '%') { | |
238 $name = substr($argument, 1, -1); | |
239 if (!isset($this->parameters[$name])) { | |
240 $arguments[$key] = $this->getParameter($name); | |
241 // This can never be reached as getParameter() throws an Exception, | |
242 // because we already checked that the parameter is not set above. | |
243 } | |
244 $argument = $this->parameters[$name]; | |
245 $arguments[$key] = $argument; | |
246 } | |
247 | |
248 // Resolve services. | |
249 if ($argument[0] === '@') { | |
250 $id = substr($argument, 1); | |
251 $invalid_behavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE; | |
252 if ($id[0] === '?') { | |
253 $id = substr($id, 1); | |
254 $invalid_behavior = ContainerInterface::NULL_ON_INVALID_REFERENCE; | |
255 } | |
256 if (isset($this->services[$id])) { | |
257 $arguments[$key] = $this->services[$id]; | |
258 } | |
259 else { | |
260 $arguments[$key] = $this->get($id, $invalid_behavior); | |
261 } | |
262 } | |
263 } | |
264 | |
265 return $arguments; | |
266 } | |
267 | |
268 } |