Mercurial > hg > isophonics-drupal-site
comparison core/lib/Drupal/Core/DependencyInjection/YamlFileLoader.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children | 1fec387a4317 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4c8ae668cc8c |
---|---|
1 <?php | |
2 // @codingStandardsIgnoreFile | |
3 | |
4 namespace Drupal\Core\DependencyInjection; | |
5 | |
6 use Drupal\Component\FileCache\FileCacheFactory; | |
7 use Drupal\Core\Serialization\Yaml; | |
8 use Symfony\Component\DependencyInjection\Alias; | |
9 use Symfony\Component\DependencyInjection\ContainerInterface; | |
10 use Symfony\Component\DependencyInjection\Definition; | |
11 use Symfony\Component\DependencyInjection\DefinitionDecorator; | |
12 use Symfony\Component\DependencyInjection\Reference; | |
13 use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; | |
14 | |
15 /** | |
16 * YamlFileLoader loads YAML files service definitions. | |
17 * | |
18 * Drupal does not use Symfony's Config component, and Symfony's dependency on | |
19 * it cannot be removed easily. Therefore, this is a partial but mostly literal | |
20 * copy of upstream, which does not depend on the Config component. | |
21 * | |
22 * @see \Symfony\Component\DependencyInjection\Loader\YamlFileLoader | |
23 * @see https://github.com/symfony/symfony/pull/10920 | |
24 * | |
25 * NOTE: 98% of this code is a literal copy of Symfony's YamlFileLoader. | |
26 * | |
27 * This file does NOT follow Drupal coding standards, so as to simplify future | |
28 * synchronizations. | |
29 */ | |
30 class YamlFileLoader | |
31 { | |
32 | |
33 /** | |
34 * @var \Drupal\Core\DependencyInjection\ContainerBuilder $container | |
35 */ | |
36 protected $container; | |
37 | |
38 /** | |
39 * File cache object. | |
40 * | |
41 * @var \Drupal\Component\FileCache\FileCacheInterface | |
42 */ | |
43 protected $fileCache; | |
44 | |
45 | |
46 public function __construct(ContainerBuilder $container) | |
47 { | |
48 $this->container = $container; | |
49 $this->fileCache = FileCacheFactory::get('container_yaml_loader'); | |
50 } | |
51 | |
52 /** | |
53 * Loads a Yaml file. | |
54 * | |
55 * @param mixed $file | |
56 * The resource | |
57 */ | |
58 public function load($file) | |
59 { | |
60 // Load from the file cache, fall back to loading the file. | |
61 $content = $this->fileCache->get($file); | |
62 if (!$content) { | |
63 $content = $this->loadFile($file); | |
64 $this->fileCache->set($file, $content); | |
65 } | |
66 | |
67 // Not supported. | |
68 //$this->container->addResource(new FileResource($path)); | |
69 | |
70 // empty file | |
71 if (null === $content) { | |
72 return; | |
73 } | |
74 | |
75 // imports | |
76 // Not supported. | |
77 //$this->parseImports($content, $file); | |
78 | |
79 // parameters | |
80 if (isset($content['parameters'])) { | |
81 if (!is_array($content['parameters'])) { | |
82 throw new InvalidArgumentException(sprintf('The "parameters" key should contain an array in %s. Check your YAML syntax.', $file)); | |
83 } | |
84 | |
85 foreach ($content['parameters'] as $key => $value) { | |
86 $this->container->setParameter($key, $this->resolveServices($value)); | |
87 } | |
88 } | |
89 | |
90 // extensions | |
91 // Not supported. | |
92 //$this->loadFromExtensions($content); | |
93 | |
94 // services | |
95 $this->parseDefinitions($content, $file); | |
96 } | |
97 | |
98 /** | |
99 * Parses definitions | |
100 * | |
101 * @param array $content | |
102 * @param string $file | |
103 */ | |
104 private function parseDefinitions($content, $file) | |
105 { | |
106 if (!isset($content['services'])) { | |
107 return; | |
108 } | |
109 | |
110 if (!is_array($content['services'])) { | |
111 throw new InvalidArgumentException(sprintf('The "services" key should contain an array in %s. Check your YAML syntax.', $file)); | |
112 } | |
113 | |
114 // Some extensions split up their dependencies into multiple files. | |
115 if (isset($content['_provider'])) { | |
116 $provider = $content['_provider']; | |
117 } | |
118 else { | |
119 $basename = basename($file); | |
120 list($provider, ) = explode('.', $basename, 2); | |
121 } | |
122 foreach ($content['services'] as $id => $service) { | |
123 $service['tags'][] = ['name' => '_provider', 'provider' => $provider]; | |
124 $this->parseDefinition($id, $service, $file); | |
125 } | |
126 } | |
127 | |
128 /** | |
129 * Parses a definition. | |
130 * | |
131 * @param string $id | |
132 * @param array $service | |
133 * @param string $file | |
134 * | |
135 * @throws InvalidArgumentException | |
136 * When tags are invalid. | |
137 */ | |
138 private function parseDefinition($id, $service, $file) | |
139 { | |
140 if (is_string($service) && 0 === strpos($service, '@')) { | |
141 $this->container->setAlias($id, substr($service, 1)); | |
142 | |
143 return; | |
144 } | |
145 | |
146 if (!is_array($service)) { | |
147 throw new InvalidArgumentException(sprintf('A service definition must be an array or a string starting with "@" but %s found for service "%s" in %s. Check your YAML syntax.', gettype($service), $id, $file)); | |
148 } | |
149 | |
150 if (isset($service['alias'])) { | |
151 $public = !array_key_exists('public', $service) || (bool) $service['public']; | |
152 $this->container->setAlias($id, new Alias($service['alias'], $public)); | |
153 | |
154 return; | |
155 } | |
156 | |
157 if (isset($service['parent'])) { | |
158 $definition = new DefinitionDecorator($service['parent']); | |
159 } else { | |
160 $definition = new Definition(); | |
161 } | |
162 | |
163 if (isset($service['class'])) { | |
164 $definition->setClass($service['class']); | |
165 } | |
166 | |
167 if (isset($service['shared'])) { | |
168 $definition->setShared($service['shared']); | |
169 } | |
170 | |
171 if (isset($service['synthetic'])) { | |
172 $definition->setSynthetic($service['synthetic']); | |
173 } | |
174 | |
175 if (isset($service['lazy'])) { | |
176 $definition->setLazy($service['lazy']); | |
177 } | |
178 | |
179 if (isset($service['public'])) { | |
180 $definition->setPublic($service['public']); | |
181 } | |
182 | |
183 if (isset($service['abstract'])) { | |
184 $definition->setAbstract($service['abstract']); | |
185 } | |
186 | |
187 if (array_key_exists('deprecated', $service)) { | |
188 $definition->setDeprecated(true, $service['deprecated']); | |
189 } | |
190 | |
191 if (isset($service['factory'])) { | |
192 if (is_string($service['factory'])) { | |
193 if (strpos($service['factory'], ':') !== false && strpos($service['factory'], '::') === false) { | |
194 $parts = explode(':', $service['factory']); | |
195 $definition->setFactory(array($this->resolveServices('@'.$parts[0]), $parts[1])); | |
196 } else { | |
197 $definition->setFactory($service['factory']); | |
198 } | |
199 } else { | |
200 $definition->setFactory(array($this->resolveServices($service['factory'][0]), $service['factory'][1])); | |
201 } | |
202 } | |
203 | |
204 if (isset($service['factory_class'])) { | |
205 $definition->setFactory($service['factory_class']); | |
206 } | |
207 | |
208 if (isset($service['factory_method'])) { | |
209 $definition->setFactory($service['factory_method']); | |
210 } | |
211 | |
212 if (isset($service['factory_service'])) { | |
213 $definition->setFactory($service['factory_service']); | |
214 } | |
215 | |
216 if (isset($service['file'])) { | |
217 $definition->setFile($service['file']); | |
218 } | |
219 | |
220 if (isset($service['arguments'])) { | |
221 $definition->setArguments($this->resolveServices($service['arguments'])); | |
222 } | |
223 | |
224 if (isset($service['properties'])) { | |
225 $definition->setProperties($this->resolveServices($service['properties'])); | |
226 } | |
227 | |
228 if (isset($service['configurator'])) { | |
229 if (is_string($service['configurator'])) { | |
230 $definition->setConfigurator($service['configurator']); | |
231 } else { | |
232 $definition->setConfigurator(array($this->resolveServices($service['configurator'][0]), $service['configurator'][1])); | |
233 } | |
234 } | |
235 | |
236 if (isset($service['calls'])) { | |
237 if (!is_array($service['calls'])) { | |
238 throw new InvalidArgumentException(sprintf('Parameter "calls" must be an array for service "%s" in %s. Check your YAML syntax.', $id, $file)); | |
239 } | |
240 | |
241 foreach ($service['calls'] as $call) { | |
242 if (isset($call['method'])) { | |
243 $method = $call['method']; | |
244 $args = isset($call['arguments']) ? $this->resolveServices($call['arguments']) : array(); | |
245 } else { | |
246 $method = $call[0]; | |
247 $args = isset($call[1]) ? $this->resolveServices($call[1]) : array(); | |
248 } | |
249 | |
250 $definition->addMethodCall($method, $args); | |
251 } | |
252 } | |
253 | |
254 if (isset($service['tags'])) { | |
255 if (!is_array($service['tags'])) { | |
256 throw new InvalidArgumentException(sprintf('Parameter "tags" must be an array for service "%s" in %s. Check your YAML syntax.', $id, $file)); | |
257 } | |
258 | |
259 foreach ($service['tags'] as $tag) { | |
260 if (!is_array($tag)) { | |
261 throw new InvalidArgumentException(sprintf('A "tags" entry must be an array for service "%s" in %s. Check your YAML syntax.', $id, $file)); | |
262 } | |
263 | |
264 if (!isset($tag['name'])) { | |
265 throw new InvalidArgumentException(sprintf('A "tags" entry is missing a "name" key for service "%s" in %s.', $id, $file)); | |
266 } | |
267 | |
268 $name = $tag['name']; | |
269 unset($tag['name']); | |
270 | |
271 foreach ($tag as $attribute => $value) { | |
272 if (!is_scalar($value) && null !== $value) { | |
273 throw new InvalidArgumentException(sprintf('A "tags" attribute must be of a scalar-type for service "%s", tag "%s", attribute "%s" in %s. Check your YAML syntax.', $id, $name, $attribute, $file)); | |
274 } | |
275 } | |
276 | |
277 $definition->addTag($name, $tag); | |
278 } | |
279 } | |
280 | |
281 if (isset($service['decorates'])) { | |
282 $renameId = isset($service['decoration_inner_name']) ? $service['decoration_inner_name'] : null; | |
283 $priority = isset($service['decoration_priority']) ? $service['decoration_priority'] : 0; | |
284 $definition->setDecoratedService($service['decorates'], $renameId, $priority); | |
285 } | |
286 | |
287 if (isset($service['autowire'])) { | |
288 $definition->setAutowired($service['autowire']); | |
289 } | |
290 | |
291 if (isset($service['autowiring_types'])) { | |
292 if (is_string($service['autowiring_types'])) { | |
293 $definition->addAutowiringType($service['autowiring_types']); | |
294 } else { | |
295 if (!is_array($service['autowiring_types'])) { | |
296 throw new InvalidArgumentException(sprintf('Parameter "autowiring_types" must be a string or an array for service "%s" in %s. Check your YAML syntax.', $id, $file)); | |
297 } | |
298 | |
299 foreach ($service['autowiring_types'] as $autowiringType) { | |
300 if (!is_string($autowiringType)) { | |
301 throw new InvalidArgumentException(sprintf('A "autowiring_types" attribute must be of type string for service "%s" in %s. Check your YAML syntax.', $id, $file)); | |
302 } | |
303 | |
304 $definition->addAutowiringType($autowiringType); | |
305 } | |
306 } | |
307 } | |
308 | |
309 $this->container->setDefinition($id, $definition); | |
310 } | |
311 | |
312 /** | |
313 * Loads a YAML file. | |
314 * | |
315 * @param string $file | |
316 * | |
317 * @return array The file content | |
318 * | |
319 * @throws InvalidArgumentException | |
320 * When the given file is not a local file or when it does not exist. | |
321 */ | |
322 protected function loadFile($file) | |
323 { | |
324 if (!stream_is_local($file)) { | |
325 throw new InvalidArgumentException(sprintf('This is not a local file "%s".', $file)); | |
326 } | |
327 | |
328 if (!file_exists($file)) { | |
329 throw new InvalidArgumentException(sprintf('The service file "%s" is not valid.', $file)); | |
330 } | |
331 | |
332 return $this->validate(Yaml::decode(file_get_contents($file)), $file); | |
333 } | |
334 | |
335 /** | |
336 * Validates a YAML file. | |
337 * | |
338 * @param mixed $content | |
339 * @param string $file | |
340 * | |
341 * @return array | |
342 * | |
343 * @throws InvalidArgumentException | |
344 * When service file is not valid. | |
345 */ | |
346 private function validate($content, $file) | |
347 { | |
348 if (null === $content) { | |
349 return $content; | |
350 } | |
351 | |
352 if (!is_array($content)) { | |
353 throw new InvalidArgumentException(sprintf('The service file "%s" is not valid. It should contain an array. Check your YAML syntax.', $file)); | |
354 } | |
355 | |
356 if ($invalid_keys = array_diff_key($content, array('parameters' => 1, 'services' => 1))) { | |
357 throw new InvalidArgumentException(sprintf('The service file "%s" is not valid: it contains invalid keys %s. Services have to be added under "services" and Parameters under "parameters".', $file, $invalid_keys)); | |
358 } | |
359 | |
360 return $content; | |
361 } | |
362 | |
363 /** | |
364 * Resolves services. | |
365 * | |
366 * @param string|array $value | |
367 * | |
368 * @return array|string|Reference | |
369 */ | |
370 private function resolveServices($value) | |
371 { | |
372 if (is_array($value)) { | |
373 $value = array_map(array($this, 'resolveServices'), $value); | |
374 } elseif (is_string($value) && 0 === strpos($value, '@=')) { | |
375 // Not supported. | |
376 //return new Expression(substr($value, 2)); | |
377 throw new InvalidArgumentException(sprintf("'%s' is an Expression, but expressions are not supported.", $value)); | |
378 } elseif (is_string($value) && 0 === strpos($value, '@')) { | |
379 if (0 === strpos($value, '@@')) { | |
380 $value = substr($value, 1); | |
381 $invalidBehavior = null; | |
382 } elseif (0 === strpos($value, '@?')) { | |
383 $value = substr($value, 2); | |
384 $invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE; | |
385 } else { | |
386 $value = substr($value, 1); | |
387 $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE; | |
388 } | |
389 | |
390 if ('=' === substr($value, -1)) { | |
391 $value = substr($value, 0, -1); | |
392 $strict = false; | |
393 } else { | |
394 $strict = true; | |
395 } | |
396 | |
397 if (null !== $invalidBehavior) { | |
398 $value = new Reference($value, $invalidBehavior, $strict); | |
399 } | |
400 } | |
401 | |
402 return $value; | |
403 } | |
404 | |
405 } |