Fix bug in style changes for the Use cases on the live site.
[yaffs-website] / vendor / symfony / dependency-injection / Loader / YamlFileLoader.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\Loader;
13
14 use Symfony\Component\DependencyInjection\DefinitionDecorator;
15 use Symfony\Component\DependencyInjection\Alias;
16 use Symfony\Component\DependencyInjection\ContainerInterface;
17 use Symfony\Component\DependencyInjection\Definition;
18 use Symfony\Component\DependencyInjection\Reference;
19 use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
20 use Symfony\Component\DependencyInjection\Exception\RuntimeException;
21 use Symfony\Component\Config\Resource\FileResource;
22 use Symfony\Component\Yaml\Exception\ParseException;
23 use Symfony\Component\Yaml\Parser as YamlParser;
24 use Symfony\Component\ExpressionLanguage\Expression;
25
26 /**
27  * YamlFileLoader loads YAML files service definitions.
28  *
29  * The YAML format does not support anonymous services (cf. the XML loader).
30  *
31  * @author Fabien Potencier <fabien@symfony.com>
32  */
33 class YamlFileLoader extends FileLoader
34 {
35     private $yamlParser;
36
37     /**
38      * {@inheritdoc}
39      */
40     public function load($resource, $type = null)
41     {
42         $path = $this->locator->locate($resource);
43
44         $content = $this->loadFile($path);
45
46         $this->container->addResource(new FileResource($path));
47
48         // empty file
49         if (null === $content) {
50             return;
51         }
52
53         // imports
54         $this->parseImports($content, $path);
55
56         // parameters
57         if (isset($content['parameters'])) {
58             if (!is_array($content['parameters'])) {
59                 throw new InvalidArgumentException(sprintf('The "parameters" key should contain an array in %s. Check your YAML syntax.', $resource));
60             }
61
62             foreach ($content['parameters'] as $key => $value) {
63                 $this->container->setParameter($key, $this->resolveServices($value));
64             }
65         }
66
67         // extensions
68         $this->loadFromExtensions($content);
69
70         // services
71         $this->parseDefinitions($content, $resource);
72     }
73
74     /**
75      * {@inheritdoc}
76      */
77     public function supports($resource, $type = null)
78     {
79         return is_string($resource) && in_array(pathinfo($resource, PATHINFO_EXTENSION), array('yml', 'yaml'), true);
80     }
81
82     /**
83      * Parses all imports.
84      *
85      * @param array  $content
86      * @param string $file
87      */
88     private function parseImports(array $content, $file)
89     {
90         if (!isset($content['imports'])) {
91             return;
92         }
93
94         if (!is_array($content['imports'])) {
95             throw new InvalidArgumentException(sprintf('The "imports" key should contain an array in %s. Check your YAML syntax.', $file));
96         }
97
98         $defaultDirectory = dirname($file);
99         foreach ($content['imports'] as $import) {
100             if (!is_array($import)) {
101                 throw new InvalidArgumentException(sprintf('The values in the "imports" key should be arrays in %s. Check your YAML syntax.', $file));
102             }
103
104             $this->setCurrentDir($defaultDirectory);
105             $this->import($import['resource'], null, isset($import['ignore_errors']) ? (bool) $import['ignore_errors'] : false, $file);
106         }
107     }
108
109     /**
110      * Parses definitions.
111      *
112      * @param array  $content
113      * @param string $file
114      */
115     private function parseDefinitions(array $content, $file)
116     {
117         if (!isset($content['services'])) {
118             return;
119         }
120
121         if (!is_array($content['services'])) {
122             throw new InvalidArgumentException(sprintf('The "services" key should contain an array in %s. Check your YAML syntax.', $file));
123         }
124
125         foreach ($content['services'] as $id => $service) {
126             $this->parseDefinition($id, $service, $file);
127         }
128     }
129
130     /**
131      * Parses a definition.
132      *
133      * @param string       $id
134      * @param array|string $service
135      * @param string       $file
136      *
137      * @throws InvalidArgumentException When tags are invalid
138      */
139     private function parseDefinition($id, $service, $file)
140     {
141         if (is_string($service) && 0 === strpos($service, '@')) {
142             $this->container->setAlias($id, substr($service, 1));
143
144             return;
145         }
146
147         if (!is_array($service)) {
148             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));
149         }
150
151         if (isset($service['alias'])) {
152             $public = !array_key_exists('public', $service) || (bool) $service['public'];
153             $this->container->setAlias($id, new Alias($service['alias'], $public));
154
155             return;
156         }
157
158         if (isset($service['parent'])) {
159             $definition = new DefinitionDecorator($service['parent']);
160         } else {
161             $definition = new Definition();
162         }
163
164         if (isset($service['class'])) {
165             $definition->setClass($service['class']);
166         }
167
168         if (isset($service['shared'])) {
169             $definition->setShared($service['shared']);
170         }
171
172         if (isset($service['scope'])) {
173             if ('request' !== $id) {
174                 @trigger_error(sprintf('The "scope" key of service "%s" in file "%s" is deprecated since version 2.8 and will be removed in 3.0.', $id, $file), E_USER_DEPRECATED);
175             }
176             $definition->setScope($service['scope'], false);
177         }
178
179         if (isset($service['synthetic'])) {
180             $definition->setSynthetic($service['synthetic']);
181         }
182
183         if (isset($service['synchronized'])) {
184             @trigger_error(sprintf('The "synchronized" key of service "%s" in file "%s" is deprecated since version 2.7 and will be removed in 3.0.', $id, $file), E_USER_DEPRECATED);
185             $definition->setSynchronized($service['synchronized'], 'request' !== $id);
186         }
187
188         if (isset($service['lazy'])) {
189             $definition->setLazy($service['lazy']);
190         }
191
192         if (isset($service['public'])) {
193             $definition->setPublic($service['public']);
194         }
195
196         if (isset($service['abstract'])) {
197             $definition->setAbstract($service['abstract']);
198         }
199
200         if (array_key_exists('deprecated', $service)) {
201             $definition->setDeprecated(true, $service['deprecated']);
202         }
203
204         if (isset($service['factory'])) {
205             if (is_string($service['factory'])) {
206                 if (strpos($service['factory'], ':') !== false && strpos($service['factory'], '::') === false) {
207                     $parts = explode(':', $service['factory']);
208                     $definition->setFactory(array($this->resolveServices('@'.$parts[0]), $parts[1]));
209                 } else {
210                     $definition->setFactory($service['factory']);
211                 }
212             } else {
213                 $definition->setFactory(array($this->resolveServices($service['factory'][0]), $service['factory'][1]));
214             }
215         }
216
217         if (isset($service['factory_class'])) {
218             @trigger_error(sprintf('The "factory_class" key of service "%s" in file "%s" is deprecated since version 2.6 and will be removed in 3.0. Use "factory" instead.', $id, $file), E_USER_DEPRECATED);
219             $definition->setFactoryClass($service['factory_class']);
220         }
221
222         if (isset($service['factory_method'])) {
223             @trigger_error(sprintf('The "factory_method" key of service "%s" in file "%s" is deprecated since version 2.6 and will be removed in 3.0. Use "factory" instead.', $id, $file), E_USER_DEPRECATED);
224             $definition->setFactoryMethod($service['factory_method']);
225         }
226
227         if (isset($service['factory_service'])) {
228             @trigger_error(sprintf('The "factory_service" key of service "%s" in file "%s" is deprecated since version 2.6 and will be removed in 3.0. Use "factory" instead.', $id, $file), E_USER_DEPRECATED);
229             $definition->setFactoryService($service['factory_service']);
230         }
231
232         if (isset($service['file'])) {
233             $definition->setFile($service['file']);
234         }
235
236         if (isset($service['arguments'])) {
237             $definition->setArguments($this->resolveServices($service['arguments']));
238         }
239
240         if (isset($service['properties'])) {
241             $definition->setProperties($this->resolveServices($service['properties']));
242         }
243
244         if (isset($service['configurator'])) {
245             if (is_string($service['configurator'])) {
246                 $definition->setConfigurator($service['configurator']);
247             } else {
248                 $definition->setConfigurator(array($this->resolveServices($service['configurator'][0]), $service['configurator'][1]));
249             }
250         }
251
252         if (isset($service['calls'])) {
253             if (!is_array($service['calls'])) {
254                 throw new InvalidArgumentException(sprintf('Parameter "calls" must be an array for service "%s" in %s. Check your YAML syntax.', $id, $file));
255             }
256
257             foreach ($service['calls'] as $call) {
258                 if (isset($call['method'])) {
259                     $method = $call['method'];
260                     $args = isset($call['arguments']) ? $this->resolveServices($call['arguments']) : array();
261                 } else {
262                     $method = $call[0];
263                     $args = isset($call[1]) ? $this->resolveServices($call[1]) : array();
264                 }
265
266                 $definition->addMethodCall($method, $args);
267             }
268         }
269
270         if (isset($service['tags'])) {
271             if (!is_array($service['tags'])) {
272                 throw new InvalidArgumentException(sprintf('Parameter "tags" must be an array for service "%s" in %s. Check your YAML syntax.', $id, $file));
273             }
274
275             foreach ($service['tags'] as $tag) {
276                 if (!is_array($tag)) {
277                     throw new InvalidArgumentException(sprintf('A "tags" entry must be an array for service "%s" in %s. Check your YAML syntax.', $id, $file));
278                 }
279
280                 if (!isset($tag['name'])) {
281                     throw new InvalidArgumentException(sprintf('A "tags" entry is missing a "name" key for service "%s" in %s.', $id, $file));
282                 }
283
284                 if (!is_string($tag['name']) || '' === $tag['name']) {
285                     throw new InvalidArgumentException(sprintf('The tag name for service "%s" in %s must be a non-empty string.', $id, $file));
286                 }
287
288                 $name = $tag['name'];
289                 unset($tag['name']);
290
291                 foreach ($tag as $attribute => $value) {
292                     if (!is_scalar($value) && null !== $value) {
293                         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));
294                     }
295                 }
296
297                 $definition->addTag($name, $tag);
298             }
299         }
300
301         if (isset($service['decorates'])) {
302             if ('' !== $service['decorates'] && '@' === $service['decorates'][0]) {
303                 throw new InvalidArgumentException(sprintf('The value of the "decorates" option for the "%s" service must be the id of the service without the "@" prefix (replace "%s" with "%s").', $id, $service['decorates'], substr($service['decorates'], 1)));
304             }
305
306             $renameId = isset($service['decoration_inner_name']) ? $service['decoration_inner_name'] : null;
307             $priority = isset($service['decoration_priority']) ? $service['decoration_priority'] : 0;
308             $definition->setDecoratedService($service['decorates'], $renameId, $priority);
309         }
310
311         if (isset($service['autowire'])) {
312             $definition->setAutowired($service['autowire']);
313         }
314
315         if (isset($service['autowiring_types'])) {
316             if (is_string($service['autowiring_types'])) {
317                 $definition->addAutowiringType($service['autowiring_types']);
318             } else {
319                 if (!is_array($service['autowiring_types'])) {
320                     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));
321                 }
322
323                 foreach ($service['autowiring_types'] as $autowiringType) {
324                     if (!is_string($autowiringType)) {
325                         throw new InvalidArgumentException(sprintf('A "autowiring_types" attribute must be of type string for service "%s" in %s. Check your YAML syntax.', $id, $file));
326                     }
327
328                     $definition->addAutowiringType($autowiringType);
329                 }
330             }
331         }
332
333         $this->container->setDefinition($id, $definition);
334     }
335
336     /**
337      * Loads a YAML file.
338      *
339      * @param string $file
340      *
341      * @return array The file content
342      *
343      * @throws InvalidArgumentException when the given file is not a local file or when it does not exist
344      */
345     protected function loadFile($file)
346     {
347         if (!class_exists('Symfony\Component\Yaml\Parser')) {
348             throw new RuntimeException('Unable to load YAML config files as the Symfony Yaml Component is not installed.');
349         }
350
351         if (!stream_is_local($file)) {
352             throw new InvalidArgumentException(sprintf('This is not a local file "%s".', $file));
353         }
354
355         if (!file_exists($file)) {
356             throw new InvalidArgumentException(sprintf('The file "%s" does not exist.', $file));
357         }
358
359         if (null === $this->yamlParser) {
360             $this->yamlParser = new YamlParser();
361         }
362
363         try {
364             $configuration = $this->yamlParser->parse(file_get_contents($file));
365         } catch (ParseException $e) {
366             throw new InvalidArgumentException(sprintf('The file "%s" does not contain valid YAML.', $file), 0, $e);
367         }
368
369         return $this->validate($configuration, $file);
370     }
371
372     /**
373      * Validates a YAML file.
374      *
375      * @param mixed  $content
376      * @param string $file
377      *
378      * @return array
379      *
380      * @throws InvalidArgumentException When service file is not valid
381      */
382     private function validate($content, $file)
383     {
384         if (null === $content) {
385             return $content;
386         }
387
388         if (!is_array($content)) {
389             throw new InvalidArgumentException(sprintf('The service file "%s" is not valid. It should contain an array. Check your YAML syntax.', $file));
390         }
391
392         foreach ($content as $namespace => $data) {
393             if (in_array($namespace, array('imports', 'parameters', 'services'))) {
394                 continue;
395             }
396
397             if (!$this->container->hasExtension($namespace)) {
398                 $extensionNamespaces = array_filter(array_map(function ($ext) { return $ext->getAlias(); }, $this->container->getExtensions()));
399                 throw new InvalidArgumentException(sprintf(
400                     'There is no extension able to load the configuration for "%s" (in %s). Looked for namespace "%s", found %s',
401                     $namespace,
402                     $file,
403                     $namespace,
404                     $extensionNamespaces ? sprintf('"%s"', implode('", "', $extensionNamespaces)) : 'none'
405                 ));
406             }
407         }
408
409         return $content;
410     }
411
412     /**
413      * Resolves services.
414      *
415      * @param string|array $value
416      *
417      * @return array|string|Reference
418      */
419     private function resolveServices($value)
420     {
421         if (is_array($value)) {
422             $value = array_map(array($this, 'resolveServices'), $value);
423         } elseif (is_string($value) && 0 === strpos($value, '@=')) {
424             return new Expression(substr($value, 2));
425         } elseif (is_string($value) && 0 === strpos($value, '@')) {
426             if (0 === strpos($value, '@@')) {
427                 $value = substr($value, 1);
428                 $invalidBehavior = null;
429             } elseif (0 === strpos($value, '@?')) {
430                 $value = substr($value, 2);
431                 $invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE;
432             } else {
433                 $value = substr($value, 1);
434                 $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE;
435             }
436
437             if ('=' === substr($value, -1)) {
438                 $value = substr($value, 0, -1);
439                 $strict = false;
440             } else {
441                 $strict = true;
442             }
443
444             if (null !== $invalidBehavior) {
445                 $value = new Reference($value, $invalidBehavior, $strict);
446             }
447         }
448
449         return $value;
450     }
451
452     /**
453      * Loads from Extensions.
454      *
455      * @param array $content
456      */
457     private function loadFromExtensions(array $content)
458     {
459         foreach ($content as $namespace => $values) {
460             if (in_array($namespace, array('imports', 'parameters', 'services'))) {
461                 continue;
462             }
463
464             if (!is_array($values)) {
465                 $values = array();
466             }
467
468             $this->container->loadFromExtension($namespace, $values);
469         }
470     }
471 }