Mercurial > hg > isophonics-drupal-site
comparison vendor/symfony/routing/Loader/XmlFileLoader.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children | 7a779792577d |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4c8ae668cc8c |
---|---|
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\Routing\Loader; | |
13 | |
14 use Symfony\Component\Routing\RouteCollection; | |
15 use Symfony\Component\Routing\Route; | |
16 use Symfony\Component\Config\Resource\FileResource; | |
17 use Symfony\Component\Config\Loader\FileLoader; | |
18 use Symfony\Component\Config\Util\XmlUtils; | |
19 | |
20 /** | |
21 * XmlFileLoader loads XML routing files. | |
22 * | |
23 * @author Fabien Potencier <fabien@symfony.com> | |
24 * @author Tobias Schultze <http://tobion.de> | |
25 */ | |
26 class XmlFileLoader extends FileLoader | |
27 { | |
28 const NAMESPACE_URI = 'http://symfony.com/schema/routing'; | |
29 const SCHEME_PATH = '/schema/routing/routing-1.0.xsd'; | |
30 | |
31 /** | |
32 * Loads an XML file. | |
33 * | |
34 * @param string $file An XML file path | |
35 * @param string|null $type The resource type | |
36 * | |
37 * @return RouteCollection A RouteCollection instance | |
38 * | |
39 * @throws \InvalidArgumentException When the file cannot be loaded or when the XML cannot be | |
40 * parsed because it does not validate against the scheme. | |
41 */ | |
42 public function load($file, $type = null) | |
43 { | |
44 $path = $this->locator->locate($file); | |
45 | |
46 $xml = $this->loadFile($path); | |
47 | |
48 $collection = new RouteCollection(); | |
49 $collection->addResource(new FileResource($path)); | |
50 | |
51 // process routes and imports | |
52 foreach ($xml->documentElement->childNodes as $node) { | |
53 if (!$node instanceof \DOMElement) { | |
54 continue; | |
55 } | |
56 | |
57 $this->parseNode($collection, $node, $path, $file); | |
58 } | |
59 | |
60 return $collection; | |
61 } | |
62 | |
63 /** | |
64 * Parses a node from a loaded XML file. | |
65 * | |
66 * @param RouteCollection $collection Collection to associate with the node | |
67 * @param \DOMElement $node Element to parse | |
68 * @param string $path Full path of the XML file being processed | |
69 * @param string $file Loaded file name | |
70 * | |
71 * @throws \InvalidArgumentException When the XML is invalid | |
72 */ | |
73 protected function parseNode(RouteCollection $collection, \DOMElement $node, $path, $file) | |
74 { | |
75 if (self::NAMESPACE_URI !== $node->namespaceURI) { | |
76 return; | |
77 } | |
78 | |
79 switch ($node->localName) { | |
80 case 'route': | |
81 $this->parseRoute($collection, $node, $path); | |
82 break; | |
83 case 'import': | |
84 $this->parseImport($collection, $node, $path, $file); | |
85 break; | |
86 default: | |
87 throw new \InvalidArgumentException(sprintf('Unknown tag "%s" used in file "%s". Expected "route" or "import".', $node->localName, $path)); | |
88 } | |
89 } | |
90 | |
91 /** | |
92 * {@inheritdoc} | |
93 */ | |
94 public function supports($resource, $type = null) | |
95 { | |
96 return is_string($resource) && 'xml' === pathinfo($resource, PATHINFO_EXTENSION) && (!$type || 'xml' === $type); | |
97 } | |
98 | |
99 /** | |
100 * Parses a route and adds it to the RouteCollection. | |
101 * | |
102 * @param RouteCollection $collection RouteCollection instance | |
103 * @param \DOMElement $node Element to parse that represents a Route | |
104 * @param string $path Full path of the XML file being processed | |
105 * | |
106 * @throws \InvalidArgumentException When the XML is invalid | |
107 */ | |
108 protected function parseRoute(RouteCollection $collection, \DOMElement $node, $path) | |
109 { | |
110 if ('' === ($id = $node->getAttribute('id')) || !$node->hasAttribute('path')) { | |
111 throw new \InvalidArgumentException(sprintf('The <route> element in file "%s" must have an "id" and a "path" attribute.', $path)); | |
112 } | |
113 | |
114 $schemes = preg_split('/[\s,\|]++/', $node->getAttribute('schemes'), -1, PREG_SPLIT_NO_EMPTY); | |
115 $methods = preg_split('/[\s,\|]++/', $node->getAttribute('methods'), -1, PREG_SPLIT_NO_EMPTY); | |
116 | |
117 list($defaults, $requirements, $options, $condition) = $this->parseConfigs($node, $path); | |
118 | |
119 $route = new Route($node->getAttribute('path'), $defaults, $requirements, $options, $node->getAttribute('host'), $schemes, $methods, $condition); | |
120 $collection->add($id, $route); | |
121 } | |
122 | |
123 /** | |
124 * Parses an import and adds the routes in the resource to the RouteCollection. | |
125 * | |
126 * @param RouteCollection $collection RouteCollection instance | |
127 * @param \DOMElement $node Element to parse that represents a Route | |
128 * @param string $path Full path of the XML file being processed | |
129 * @param string $file Loaded file name | |
130 * | |
131 * @throws \InvalidArgumentException When the XML is invalid | |
132 */ | |
133 protected function parseImport(RouteCollection $collection, \DOMElement $node, $path, $file) | |
134 { | |
135 if ('' === $resource = $node->getAttribute('resource')) { | |
136 throw new \InvalidArgumentException(sprintf('The <import> element in file "%s" must have a "resource" attribute.', $path)); | |
137 } | |
138 | |
139 $type = $node->getAttribute('type'); | |
140 $prefix = $node->getAttribute('prefix'); | |
141 $host = $node->hasAttribute('host') ? $node->getAttribute('host') : null; | |
142 $schemes = $node->hasAttribute('schemes') ? preg_split('/[\s,\|]++/', $node->getAttribute('schemes'), -1, PREG_SPLIT_NO_EMPTY) : null; | |
143 $methods = $node->hasAttribute('methods') ? preg_split('/[\s,\|]++/', $node->getAttribute('methods'), -1, PREG_SPLIT_NO_EMPTY) : null; | |
144 | |
145 list($defaults, $requirements, $options, $condition) = $this->parseConfigs($node, $path); | |
146 | |
147 $this->setCurrentDir(dirname($path)); | |
148 | |
149 $subCollection = $this->import($resource, ('' !== $type ? $type : null), false, $file); | |
150 /* @var $subCollection RouteCollection */ | |
151 $subCollection->addPrefix($prefix); | |
152 if (null !== $host) { | |
153 $subCollection->setHost($host); | |
154 } | |
155 if (null !== $condition) { | |
156 $subCollection->setCondition($condition); | |
157 } | |
158 if (null !== $schemes) { | |
159 $subCollection->setSchemes($schemes); | |
160 } | |
161 if (null !== $methods) { | |
162 $subCollection->setMethods($methods); | |
163 } | |
164 $subCollection->addDefaults($defaults); | |
165 $subCollection->addRequirements($requirements); | |
166 $subCollection->addOptions($options); | |
167 | |
168 $collection->addCollection($subCollection); | |
169 } | |
170 | |
171 /** | |
172 * Loads an XML file. | |
173 * | |
174 * @param string $file An XML file path | |
175 * | |
176 * @return \DOMDocument | |
177 * | |
178 * @throws \InvalidArgumentException When loading of XML file fails because of syntax errors | |
179 * or when the XML structure is not as expected by the scheme - | |
180 * see validate() | |
181 */ | |
182 protected function loadFile($file) | |
183 { | |
184 return XmlUtils::loadFile($file, __DIR__.static::SCHEME_PATH); | |
185 } | |
186 | |
187 /** | |
188 * Parses the config elements (default, requirement, option). | |
189 * | |
190 * @param \DOMElement $node Element to parse that contains the configs | |
191 * @param string $path Full path of the XML file being processed | |
192 * | |
193 * @return array An array with the defaults as first item, requirements as second and options as third | |
194 * | |
195 * @throws \InvalidArgumentException When the XML is invalid | |
196 */ | |
197 private function parseConfigs(\DOMElement $node, $path) | |
198 { | |
199 $defaults = array(); | |
200 $requirements = array(); | |
201 $options = array(); | |
202 $condition = null; | |
203 | |
204 foreach ($node->getElementsByTagNameNS(self::NAMESPACE_URI, '*') as $n) { | |
205 if ($node !== $n->parentNode) { | |
206 continue; | |
207 } | |
208 | |
209 switch ($n->localName) { | |
210 case 'default': | |
211 if ($this->isElementValueNull($n)) { | |
212 $defaults[$n->getAttribute('key')] = null; | |
213 } else { | |
214 $defaults[$n->getAttribute('key')] = $this->parseDefaultsConfig($n, $path); | |
215 } | |
216 | |
217 break; | |
218 case 'requirement': | |
219 $requirements[$n->getAttribute('key')] = trim($n->textContent); | |
220 break; | |
221 case 'option': | |
222 $options[$n->getAttribute('key')] = trim($n->textContent); | |
223 break; | |
224 case 'condition': | |
225 $condition = trim($n->textContent); | |
226 break; | |
227 default: | |
228 throw new \InvalidArgumentException(sprintf('Unknown tag "%s" used in file "%s". Expected "default", "requirement" or "option".', $n->localName, $path)); | |
229 } | |
230 } | |
231 | |
232 return array($defaults, $requirements, $options, $condition); | |
233 } | |
234 | |
235 /** | |
236 * Parses the "default" elements. | |
237 * | |
238 * @param \DOMElement $element The "default" element to parse | |
239 * @param string $path Full path of the XML file being processed | |
240 * | |
241 * @return array|bool|float|int|string|null The parsed value of the "default" element | |
242 */ | |
243 private function parseDefaultsConfig(\DOMElement $element, $path) | |
244 { | |
245 if ($this->isElementValueNull($element)) { | |
246 return; | |
247 } | |
248 | |
249 // Check for existing element nodes in the default element. There can | |
250 // only be a single element inside a default element. So this element | |
251 // (if one was found) can safely be returned. | |
252 foreach ($element->childNodes as $child) { | |
253 if (!$child instanceof \DOMElement) { | |
254 continue; | |
255 } | |
256 | |
257 if (self::NAMESPACE_URI !== $child->namespaceURI) { | |
258 continue; | |
259 } | |
260 | |
261 return $this->parseDefaultNode($child, $path); | |
262 } | |
263 | |
264 // If the default element doesn't contain a nested "bool", "int", "float", | |
265 // "string", "list", or "map" element, the element contents will be treated | |
266 // as the string value of the associated default option. | |
267 return trim($element->textContent); | |
268 } | |
269 | |
270 /** | |
271 * Recursively parses the value of a "default" element. | |
272 * | |
273 * @param \DOMElement $node The node value | |
274 * @param string $path Full path of the XML file being processed | |
275 * | |
276 * @return array|bool|float|int|string The parsed value | |
277 * | |
278 * @throws \InvalidArgumentException when the XML is invalid | |
279 */ | |
280 private function parseDefaultNode(\DOMElement $node, $path) | |
281 { | |
282 if ($this->isElementValueNull($node)) { | |
283 return; | |
284 } | |
285 | |
286 switch ($node->localName) { | |
287 case 'bool': | |
288 return 'true' === trim($node->nodeValue) || '1' === trim($node->nodeValue); | |
289 case 'int': | |
290 return (int) trim($node->nodeValue); | |
291 case 'float': | |
292 return (float) trim($node->nodeValue); | |
293 case 'string': | |
294 return trim($node->nodeValue); | |
295 case 'list': | |
296 $list = array(); | |
297 | |
298 foreach ($node->childNodes as $element) { | |
299 if (!$element instanceof \DOMElement) { | |
300 continue; | |
301 } | |
302 | |
303 if (self::NAMESPACE_URI !== $element->namespaceURI) { | |
304 continue; | |
305 } | |
306 | |
307 $list[] = $this->parseDefaultNode($element, $path); | |
308 } | |
309 | |
310 return $list; | |
311 case 'map': | |
312 $map = array(); | |
313 | |
314 foreach ($node->childNodes as $element) { | |
315 if (!$element instanceof \DOMElement) { | |
316 continue; | |
317 } | |
318 | |
319 if (self::NAMESPACE_URI !== $element->namespaceURI) { | |
320 continue; | |
321 } | |
322 | |
323 $map[$element->getAttribute('key')] = $this->parseDefaultNode($element, $path); | |
324 } | |
325 | |
326 return $map; | |
327 default: | |
328 throw new \InvalidArgumentException(sprintf('Unknown tag "%s" used in file "%s". Expected "bool", "int", "float", "string", "list", or "map".', $node->localName, $path)); | |
329 } | |
330 } | |
331 | |
332 private function isElementValueNull(\DOMElement $element) | |
333 { | |
334 $namespaceUri = 'http://www.w3.org/2001/XMLSchema-instance'; | |
335 | |
336 if (!$element->hasAttributeNS($namespaceUri, 'nil')) { | |
337 return false; | |
338 } | |
339 | |
340 return 'true' === $element->getAttributeNS($namespaceUri, 'nil') || '1' === $element->getAttributeNS($namespaceUri, 'nil'); | |
341 } | |
342 } |