35441023de5b54fef19f1f58fee8a850d4f6d949
[yaffs-website] / vendor / symfony / dependency-injection / Dumper / YamlDumper.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\Dumper;
13
14 use Symfony\Component\DependencyInjection\Alias;
15 use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
16 use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
17 use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
18 use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
19 use Symfony\Component\DependencyInjection\ContainerInterface;
20 use Symfony\Component\DependencyInjection\Definition;
21 use Symfony\Component\DependencyInjection\Exception\RuntimeException;
22 use Symfony\Component\DependencyInjection\Parameter;
23 use Symfony\Component\DependencyInjection\Reference;
24 use Symfony\Component\ExpressionLanguage\Expression;
25 use Symfony\Component\Yaml\Dumper as YmlDumper;
26 use Symfony\Component\Yaml\Parser;
27 use Symfony\Component\Yaml\Tag\TaggedValue;
28 use Symfony\Component\Yaml\Yaml;
29
30 /**
31  * YamlDumper dumps a service container as a YAML string.
32  *
33  * @author Fabien Potencier <fabien@symfony.com>
34  */
35 class YamlDumper extends Dumper
36 {
37     private $dumper;
38
39     /**
40      * Dumps the service container as an YAML string.
41      *
42      * @return string A YAML string representing of the service container
43      */
44     public function dump(array $options = array())
45     {
46         if (!class_exists('Symfony\Component\Yaml\Dumper')) {
47             throw new RuntimeException('Unable to dump the container as the Symfony Yaml Component is not installed.');
48         }
49
50         if (null === $this->dumper) {
51             $this->dumper = new YmlDumper();
52         }
53
54         return $this->container->resolveEnvPlaceholders($this->addParameters()."\n".$this->addServices());
55     }
56
57     /**
58      * Adds a service.
59      *
60      * @param string     $id
61      * @param Definition $definition
62      *
63      * @return string
64      */
65     private function addService($id, Definition $definition)
66     {
67         $code = "    $id:\n";
68         if ($class = $definition->getClass()) {
69             if ('\\' === substr($class, 0, 1)) {
70                 $class = substr($class, 1);
71             }
72
73             $code .= sprintf("        class: %s\n", $this->dumper->dump($class));
74         }
75
76         if (!$definition->isPrivate()) {
77             $code .= sprintf("        public: %s\n", $definition->isPublic() ? 'true' : 'false');
78         }
79
80         $tagsCode = '';
81         foreach ($definition->getTags() as $name => $tags) {
82             foreach ($tags as $attributes) {
83                 $att = array();
84                 foreach ($attributes as $key => $value) {
85                     $att[] = sprintf('%s: %s', $this->dumper->dump($key), $this->dumper->dump($value));
86                 }
87                 $att = $att ? ', '.implode(', ', $att) : '';
88
89                 $tagsCode .= sprintf("            - { name: %s%s }\n", $this->dumper->dump($name), $att);
90             }
91         }
92         if ($tagsCode) {
93             $code .= "        tags:\n".$tagsCode;
94         }
95
96         if ($definition->getFile()) {
97             $code .= sprintf("        file: %s\n", $this->dumper->dump($definition->getFile()));
98         }
99
100         if ($definition->isSynthetic()) {
101             $code .= "        synthetic: true\n";
102         }
103
104         if ($definition->isDeprecated()) {
105             $code .= sprintf("        deprecated: %s\n", $this->dumper->dump($definition->getDeprecationMessage('%service_id%')));
106         }
107
108         if ($definition->isAutowired()) {
109             $code .= "        autowire: true\n";
110         }
111
112         $autowiringTypesCode = '';
113         foreach ($definition->getAutowiringTypes(false) as $autowiringType) {
114             $autowiringTypesCode .= sprintf("            - %s\n", $this->dumper->dump($autowiringType));
115         }
116         if ($autowiringTypesCode) {
117             $code .= sprintf("        autowiring_types:\n%s", $autowiringTypesCode);
118         }
119
120         if ($definition->isAutoconfigured()) {
121             $code .= "        autoconfigure: true\n";
122         }
123
124         if ($definition->isAbstract()) {
125             $code .= "        abstract: true\n";
126         }
127
128         if ($definition->isLazy()) {
129             $code .= "        lazy: true\n";
130         }
131
132         if ($definition->getArguments()) {
133             $code .= sprintf("        arguments: %s\n", $this->dumper->dump($this->dumpValue($definition->getArguments()), 0));
134         }
135
136         if ($definition->getProperties()) {
137             $code .= sprintf("        properties: %s\n", $this->dumper->dump($this->dumpValue($definition->getProperties()), 0));
138         }
139
140         if ($definition->getMethodCalls()) {
141             $code .= sprintf("        calls:\n%s\n", $this->dumper->dump($this->dumpValue($definition->getMethodCalls()), 1, 12));
142         }
143
144         if (!$definition->isShared()) {
145             $code .= "        shared: false\n";
146         }
147
148         if (null !== $decorated = $definition->getDecoratedService()) {
149             list($decorated, $renamedId, $priority) = $decorated;
150             $code .= sprintf("        decorates: %s\n", $decorated);
151             if (null !== $renamedId) {
152                 $code .= sprintf("        decoration_inner_name: %s\n", $renamedId);
153             }
154             if (0 !== $priority) {
155                 $code .= sprintf("        decoration_priority: %s\n", $priority);
156             }
157         }
158
159         if ($callable = $definition->getFactory()) {
160             $code .= sprintf("        factory: %s\n", $this->dumper->dump($this->dumpCallable($callable), 0));
161         }
162
163         if ($callable = $definition->getConfigurator()) {
164             $code .= sprintf("        configurator: %s\n", $this->dumper->dump($this->dumpCallable($callable), 0));
165         }
166
167         return $code;
168     }
169
170     /**
171      * Adds a service alias.
172      *
173      * @param string $alias
174      * @param Alias  $id
175      *
176      * @return string
177      */
178     private function addServiceAlias($alias, Alias $id)
179     {
180         if ($id->isPrivate()) {
181             return sprintf("    %s: '@%s'\n", $alias, $id);
182         }
183
184         return sprintf("    %s:\n        alias: %s\n        public: %s\n", $alias, $id, $id->isPublic() ? 'true' : 'false');
185     }
186
187     /**
188      * Adds services.
189      *
190      * @return string
191      */
192     private function addServices()
193     {
194         if (!$this->container->getDefinitions()) {
195             return '';
196         }
197
198         $code = "services:\n";
199         foreach ($this->container->getDefinitions() as $id => $definition) {
200             $code .= $this->addService($id, $definition);
201         }
202
203         $aliases = $this->container->getAliases();
204         foreach ($aliases as $alias => $id) {
205             while (isset($aliases[(string) $id])) {
206                 $id = $aliases[(string) $id];
207             }
208             $code .= $this->addServiceAlias($alias, $id);
209         }
210
211         return $code;
212     }
213
214     /**
215      * Adds parameters.
216      *
217      * @return string
218      */
219     private function addParameters()
220     {
221         if (!$this->container->getParameterBag()->all()) {
222             return '';
223         }
224
225         $parameters = $this->prepareParameters($this->container->getParameterBag()->all(), $this->container->isCompiled());
226
227         return $this->dumper->dump(array('parameters' => $parameters), 2);
228     }
229
230     /**
231      * Dumps callable to YAML format.
232      *
233      * @param callable $callable
234      *
235      * @return callable
236      */
237     private function dumpCallable($callable)
238     {
239         if (\is_array($callable)) {
240             if ($callable[0] instanceof Reference) {
241                 $callable = array($this->getServiceCall((string) $callable[0], $callable[0]), $callable[1]);
242             } else {
243                 $callable = array($callable[0], $callable[1]);
244             }
245         }
246
247         return $callable;
248     }
249
250     /**
251      * Dumps the value to YAML format.
252      *
253      * @param mixed $value
254      *
255      * @return mixed
256      *
257      * @throws RuntimeException When trying to dump object or resource
258      */
259     private function dumpValue($value)
260     {
261         if ($value instanceof ServiceClosureArgument) {
262             $value = $value->getValues()[0];
263         }
264         if ($value instanceof ArgumentInterface) {
265             if ($value instanceof TaggedIteratorArgument) {
266                 return new TaggedValue('tagged', $value->getTag());
267             }
268             if ($value instanceof IteratorArgument) {
269                 $tag = 'iterator';
270             } else {
271                 throw new RuntimeException(sprintf('Unspecified Yaml tag for type "%s".', \get_class($value)));
272             }
273
274             return new TaggedValue($tag, $this->dumpValue($value->getValues()));
275         }
276
277         if (\is_array($value)) {
278             $code = array();
279             foreach ($value as $k => $v) {
280                 $code[$k] = $this->dumpValue($v);
281             }
282
283             return $code;
284         } elseif ($value instanceof Reference) {
285             return $this->getServiceCall((string) $value, $value);
286         } elseif ($value instanceof Parameter) {
287             return $this->getParameterCall((string) $value);
288         } elseif ($value instanceof Expression) {
289             return $this->getExpressionCall((string) $value);
290         } elseif ($value instanceof Definition) {
291             return new TaggedValue('service', (new Parser())->parse("_:\n".$this->addService('_', $value), Yaml::PARSE_CUSTOM_TAGS)['_']['_']);
292         } elseif (\is_object($value) || \is_resource($value)) {
293             throw new RuntimeException('Unable to dump a service container if a parameter is an object or a resource.');
294         }
295
296         return $value;
297     }
298
299     /**
300      * Gets the service call.
301      *
302      * @param string    $id
303      * @param Reference $reference
304      *
305      * @return string
306      */
307     private function getServiceCall($id, Reference $reference = null)
308     {
309         if (null !== $reference) {
310             switch ($reference->getInvalidBehavior()) {
311                 case ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE: break;
312                 case ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE: return sprintf('@!%s', $id);
313                 default: return sprintf('@?%s', $id);
314             }
315         }
316
317         return sprintf('@%s', $id);
318     }
319
320     /**
321      * Gets parameter call.
322      *
323      * @param string $id
324      *
325      * @return string
326      */
327     private function getParameterCall($id)
328     {
329         return sprintf('%%%s%%', $id);
330     }
331
332     private function getExpressionCall($expression)
333     {
334         return sprintf('@=%s', $expression);
335     }
336
337     /**
338      * Prepares parameters.
339      *
340      * @param array $parameters
341      * @param bool  $escape
342      *
343      * @return array
344      */
345     private function prepareParameters(array $parameters, $escape = true)
346     {
347         $filtered = array();
348         foreach ($parameters as $key => $value) {
349             if (\is_array($value)) {
350                 $value = $this->prepareParameters($value, $escape);
351             } elseif ($value instanceof Reference || \is_string($value) && 0 === strpos($value, '@')) {
352                 $value = '@'.$value;
353             }
354
355             $filtered[$key] = $value;
356         }
357
358         return $escape ? $this->escape($filtered) : $filtered;
359     }
360
361     /**
362      * Escapes arguments.
363      *
364      * @return array
365      */
366     private function escape(array $arguments)
367     {
368         $args = array();
369         foreach ($arguments as $k => $v) {
370             if (\is_array($v)) {
371                 $args[$k] = $this->escape($v);
372             } elseif (\is_string($v)) {
373                 $args[$k] = str_replace('%', '%%', $v);
374             } else {
375                 $args[$k] = $v;
376             }
377         }
378
379         return $args;
380     }
381 }