Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / vendor / symfony / config / Definition / Dumper / XmlReferenceDumper.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\Config\Definition\Dumper;
13
14 use Symfony\Component\Config\Definition\ArrayNode;
15 use Symfony\Component\Config\Definition\ConfigurationInterface;
16 use Symfony\Component\Config\Definition\EnumNode;
17 use Symfony\Component\Config\Definition\NodeInterface;
18 use Symfony\Component\Config\Definition\PrototypedArrayNode;
19
20 /**
21  * Dumps a XML reference configuration for the given configuration/node instance.
22  *
23  * @author Wouter J <waldio.webdesign@gmail.com>
24  */
25 class XmlReferenceDumper
26 {
27     private $reference;
28
29     public function dump(ConfigurationInterface $configuration, $namespace = null)
30     {
31         return $this->dumpNode($configuration->getConfigTreeBuilder()->buildTree(), $namespace);
32     }
33
34     public function dumpNode(NodeInterface $node, $namespace = null)
35     {
36         $this->reference = '';
37         $this->writeNode($node, 0, true, $namespace);
38         $ref = $this->reference;
39         $this->reference = null;
40
41         return $ref;
42     }
43
44     /**
45      * @param NodeInterface $node
46      * @param int           $depth
47      * @param bool          $root      If the node is the root node
48      * @param string        $namespace The namespace of the node
49      */
50     private function writeNode(NodeInterface $node, $depth = 0, $root = false, $namespace = null)
51     {
52         $rootName = ($root ? 'config' : $node->getName());
53         $rootNamespace = ($namespace ?: ($root ? 'http://example.org/schema/dic/'.$node->getName() : null));
54
55         // xml remapping
56         if ($node->getParent()) {
57             $remapping = array_filter($node->getParent()->getXmlRemappings(), function ($mapping) use ($rootName) {
58                 return $rootName === $mapping[1];
59             });
60
61             if (\count($remapping)) {
62                 list($singular) = current($remapping);
63                 $rootName = $singular;
64             }
65         }
66         $rootName = str_replace('_', '-', $rootName);
67
68         $rootAttributes = array();
69         $rootAttributeComments = array();
70         $rootChildren = array();
71         $rootComments = array();
72
73         if ($node instanceof ArrayNode) {
74             $children = $node->getChildren();
75
76             // comments about the root node
77             if ($rootInfo = $node->getInfo()) {
78                 $rootComments[] = $rootInfo;
79             }
80
81             if ($rootNamespace) {
82                 $rootComments[] = 'Namespace: '.$rootNamespace;
83             }
84
85             // render prototyped nodes
86             if ($node instanceof PrototypedArrayNode) {
87                 $prototype = $node->getPrototype();
88
89                 $info = 'prototype';
90                 if (null !== $prototype->getInfo()) {
91                     $info .= ': '.$prototype->getInfo();
92                 }
93                 array_unshift($rootComments, $info);
94
95                 if ($key = $node->getKeyAttribute()) {
96                     $rootAttributes[$key] = str_replace('-', ' ', $rootName).' '.$key;
97                 }
98
99                 if ($prototype instanceof PrototypedArrayNode) {
100                     $prototype->setName($key);
101                     $children = array($key => $prototype);
102                 } elseif ($prototype instanceof ArrayNode) {
103                     $children = $prototype->getChildren();
104                 } else {
105                     if ($prototype->hasDefaultValue()) {
106                         $prototypeValue = $prototype->getDefaultValue();
107                     } else {
108                         switch (\get_class($prototype)) {
109                             case 'Symfony\Component\Config\Definition\ScalarNode':
110                                 $prototypeValue = 'scalar value';
111                                 break;
112
113                             case 'Symfony\Component\Config\Definition\FloatNode':
114                             case 'Symfony\Component\Config\Definition\IntegerNode':
115                                 $prototypeValue = 'numeric value';
116                                 break;
117
118                             case 'Symfony\Component\Config\Definition\BooleanNode':
119                                 $prototypeValue = 'true|false';
120                                 break;
121
122                             case 'Symfony\Component\Config\Definition\EnumNode':
123                                 $prototypeValue = implode('|', array_map('json_encode', $prototype->getValues()));
124                                 break;
125
126                             default:
127                                 $prototypeValue = 'value';
128                         }
129                     }
130                 }
131             }
132
133             // get attributes and elements
134             foreach ($children as $child) {
135                 if (!$child instanceof ArrayNode) {
136                     // get attributes
137
138                     // metadata
139                     $name = str_replace('_', '-', $child->getName());
140                     $value = '%%%%not_defined%%%%'; // use a string which isn't used in the normal world
141
142                     // comments
143                     $comments = array();
144                     if ($info = $child->getInfo()) {
145                         $comments[] = $info;
146                     }
147
148                     if ($example = $child->getExample()) {
149                         $comments[] = 'Example: '.$example;
150                     }
151
152                     if ($child->isRequired()) {
153                         $comments[] = 'Required';
154                     }
155
156                     if ($child->isDeprecated()) {
157                         $comments[] = sprintf('Deprecated (%s)', $child->getDeprecationMessage($child->getName(), $node->getPath()));
158                     }
159
160                     if ($child instanceof EnumNode) {
161                         $comments[] = 'One of '.implode('; ', array_map('json_encode', $child->getValues()));
162                     }
163
164                     if (\count($comments)) {
165                         $rootAttributeComments[$name] = implode(";\n", $comments);
166                     }
167
168                     // default values
169                     if ($child->hasDefaultValue()) {
170                         $value = $child->getDefaultValue();
171                     }
172
173                     // append attribute
174                     $rootAttributes[$name] = $value;
175                 } else {
176                     // get elements
177                     $rootChildren[] = $child;
178                 }
179             }
180         }
181
182         // render comments
183
184         // root node comment
185         if (\count($rootComments)) {
186             foreach ($rootComments as $comment) {
187                 $this->writeLine('<!-- '.$comment.' -->', $depth);
188             }
189         }
190
191         // attribute comments
192         if (\count($rootAttributeComments)) {
193             foreach ($rootAttributeComments as $attrName => $comment) {
194                 $commentDepth = $depth + 4 + \strlen($attrName) + 2;
195                 $commentLines = explode("\n", $comment);
196                 $multiline = (\count($commentLines) > 1);
197                 $comment = implode(PHP_EOL.str_repeat(' ', $commentDepth), $commentLines);
198
199                 if ($multiline) {
200                     $this->writeLine('<!--', $depth);
201                     $this->writeLine($attrName.': '.$comment, $depth + 4);
202                     $this->writeLine('-->', $depth);
203                 } else {
204                     $this->writeLine('<!-- '.$attrName.': '.$comment.' -->', $depth);
205                 }
206             }
207         }
208
209         // render start tag + attributes
210         $rootIsVariablePrototype = isset($prototypeValue);
211         $rootIsEmptyTag = (0 === \count($rootChildren) && !$rootIsVariablePrototype);
212         $rootOpenTag = '<'.$rootName;
213         if (1 >= ($attributesCount = \count($rootAttributes))) {
214             if (1 === $attributesCount) {
215                 $rootOpenTag .= sprintf(' %s="%s"', current(array_keys($rootAttributes)), $this->writeValue(current($rootAttributes)));
216             }
217
218             $rootOpenTag .= $rootIsEmptyTag ? ' />' : '>';
219
220             if ($rootIsVariablePrototype) {
221                 $rootOpenTag .= $prototypeValue.'</'.$rootName.'>';
222             }
223
224             $this->writeLine($rootOpenTag, $depth);
225         } else {
226             $this->writeLine($rootOpenTag, $depth);
227
228             $i = 1;
229
230             foreach ($rootAttributes as $attrName => $attrValue) {
231                 $attr = sprintf('%s="%s"', $attrName, $this->writeValue($attrValue));
232
233                 $this->writeLine($attr, $depth + 4);
234
235                 if ($attributesCount === $i++) {
236                     $this->writeLine($rootIsEmptyTag ? '/>' : '>', $depth);
237
238                     if ($rootIsVariablePrototype) {
239                         $rootOpenTag .= $prototypeValue.'</'.$rootName.'>';
240                     }
241                 }
242             }
243         }
244
245         // render children tags
246         foreach ($rootChildren as $child) {
247             $this->writeLine('');
248             $this->writeNode($child, $depth + 4);
249         }
250
251         // render end tag
252         if (!$rootIsEmptyTag && !$rootIsVariablePrototype) {
253             $this->writeLine('');
254
255             $rootEndTag = '</'.$rootName.'>';
256             $this->writeLine($rootEndTag, $depth);
257         }
258     }
259
260     /**
261      * Outputs a single config reference line.
262      *
263      * @param string $text
264      * @param int    $indent
265      */
266     private function writeLine($text, $indent = 0)
267     {
268         $indent = \strlen($text) + $indent;
269         $format = '%'.$indent.'s';
270
271         $this->reference .= sprintf($format, $text).PHP_EOL;
272     }
273
274     /**
275      * Renders the string conversion of the value.
276      *
277      * @param mixed $value
278      *
279      * @return string
280      */
281     private function writeValue($value)
282     {
283         if ('%%%%not_defined%%%%' === $value) {
284             return '';
285         }
286
287         if (\is_string($value) || is_numeric($value)) {
288             return $value;
289         }
290
291         if (false === $value) {
292             return 'false';
293         }
294
295         if (true === $value) {
296             return 'true';
297         }
298
299         if (null === $value) {
300             return 'null';
301         }
302
303         if (empty($value)) {
304             return '';
305         }
306
307         if (\is_array($value)) {
308             return implode(',', $value);
309         }
310     }
311 }