/vendor/symfony/src/Symfony/Component/Routing/Loader/XmlFileLoader.php

https://github.com/israelnoguera/parejas · PHP · 228 lines · 125 code · 27 blank · 76 comment · 12 complexity · 81e0105e0b54e84c76f9c86fb20635ef MD5 · raw file

  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Routing\Loader;
  11. use Symfony\Component\Routing\RouteCollection;
  12. use Symfony\Component\Routing\Route;
  13. use Symfony\Component\Config\Resource\FileResource;
  14. use Symfony\Component\Config\Loader\FileLoader;
  15. /**
  16. * XmlFileLoader loads XML routing files.
  17. *
  18. * @author Fabien Potencier <fabien@symfony.com>
  19. *
  20. * @api
  21. */
  22. class XmlFileLoader extends FileLoader
  23. {
  24. /**
  25. * Loads an XML file.
  26. *
  27. * @param string $file An XML file path
  28. * @param string $type The resource type
  29. *
  30. * @return RouteCollection A RouteCollection instance
  31. *
  32. * @throws \InvalidArgumentException When a tag can't be parsed
  33. *
  34. * @api
  35. */
  36. public function load($file, $type = null)
  37. {
  38. $path = $this->locator->locate($file);
  39. $xml = $this->loadFile($path);
  40. $collection = new RouteCollection();
  41. $collection->addResource(new FileResource($path));
  42. // process routes and imports
  43. foreach ($xml->documentElement->childNodes as $node) {
  44. if (!$node instanceof \DOMElement) {
  45. continue;
  46. }
  47. $this->parseNode($collection, $node, $path, $file);
  48. }
  49. return $collection;
  50. }
  51. /**
  52. * Parses a node from a loaded XML file.
  53. *
  54. * @param RouteCollection $collection the collection to associate with the node
  55. * @param DOMElement $node the node to parse
  56. * @param string $path the path of the XML file being processed
  57. * @param string $file
  58. */
  59. protected function parseNode(RouteCollection $collection, \DOMElement $node, $path, $file)
  60. {
  61. switch ($node->tagName) {
  62. case 'route':
  63. $this->parseRoute($collection, $node, $path);
  64. break;
  65. case 'import':
  66. $resource = (string) $node->getAttribute('resource');
  67. $type = (string) $node->getAttribute('type');
  68. $prefix = (string) $node->getAttribute('prefix');
  69. $defaults = array();
  70. $requirements = array();
  71. foreach ($node->childNodes as $n) {
  72. if (!$n instanceof \DOMElement) {
  73. continue;
  74. }
  75. switch ($n->tagName) {
  76. case 'default':
  77. $defaults[(string) $n->getAttribute('key')] = trim((string) $n->nodeValue);
  78. break;
  79. case 'requirement':
  80. $requirements[(string) $n->getAttribute('key')] = trim((string) $n->nodeValue);
  81. break;
  82. default:
  83. throw new \InvalidArgumentException(sprintf('Unable to parse tag "%s"', $n->tagName));
  84. }
  85. }
  86. $this->setCurrentDir(dirname($path));
  87. $collection->addCollection($this->import($resource, ('' !== $type ? $type : null), false, $file), $prefix, $defaults, $requirements);
  88. break;
  89. default:
  90. throw new \InvalidArgumentException(sprintf('Unable to parse tag "%s"', $node->tagName));
  91. }
  92. }
  93. /**
  94. * Returns true if this class supports the given resource.
  95. *
  96. * @param mixed $resource A resource
  97. * @param string $type The resource type
  98. *
  99. * @return Boolean True if this class supports the given resource, false otherwise
  100. *
  101. * @api
  102. */
  103. public function supports($resource, $type = null)
  104. {
  105. return is_string($resource) && 'xml' === pathinfo($resource, PATHINFO_EXTENSION) && (!$type || 'xml' === $type);
  106. }
  107. /**
  108. * Parses a route and adds it to the RouteCollection.
  109. *
  110. * @param RouteCollection $collection A RouteCollection instance
  111. * @param \DOMElement $definition Route definition
  112. * @param string $file An XML file path
  113. *
  114. * @throws \InvalidArgumentException When the definition cannot be parsed
  115. */
  116. protected function parseRoute(RouteCollection $collection, \DOMElement $definition, $file)
  117. {
  118. $defaults = array();
  119. $requirements = array();
  120. $options = array();
  121. foreach ($definition->childNodes as $node) {
  122. if (!$node instanceof \DOMElement) {
  123. continue;
  124. }
  125. switch ($node->tagName) {
  126. case 'default':
  127. $defaults[(string) $node->getAttribute('key')] = trim((string) $node->nodeValue);
  128. break;
  129. case 'option':
  130. $options[(string) $node->getAttribute('key')] = trim((string) $node->nodeValue);
  131. break;
  132. case 'requirement':
  133. $requirements[(string) $node->getAttribute('key')] = trim((string) $node->nodeValue);
  134. break;
  135. default:
  136. throw new \InvalidArgumentException(sprintf('Unable to parse tag "%s"', $node->tagName));
  137. }
  138. }
  139. $route = new Route((string) $definition->getAttribute('pattern'), $defaults, $requirements, $options);
  140. $collection->add((string) $definition->getAttribute('id'), $route);
  141. }
  142. /**
  143. * Loads an XML file.
  144. *
  145. * @param string $file An XML file path
  146. *
  147. * @return \DOMDocument
  148. *
  149. * @throws \InvalidArgumentException When loading of XML file returns error
  150. */
  151. protected function loadFile($file)
  152. {
  153. $dom = new \DOMDocument();
  154. libxml_use_internal_errors(true);
  155. if (!$dom->load($file, defined('LIBXML_COMPACT') ? LIBXML_COMPACT : 0)) {
  156. throw new \InvalidArgumentException(implode("\n", $this->getXmlErrors()));
  157. }
  158. $dom->validateOnParse = true;
  159. $dom->normalizeDocument();
  160. libxml_use_internal_errors(false);
  161. $this->validate($dom);
  162. return $dom;
  163. }
  164. /**
  165. * Validates a loaded XML file.
  166. *
  167. * @param \DOMDocument $dom A loaded XML file
  168. *
  169. * @throws \InvalidArgumentException When XML doesn't validate its XSD schema
  170. */
  171. protected function validate(\DOMDocument $dom)
  172. {
  173. $location = __DIR__.'/schema/routing/routing-1.0.xsd';
  174. $current = libxml_use_internal_errors(true);
  175. if (!$dom->schemaValidate($location)) {
  176. throw new \InvalidArgumentException(implode("\n", $this->getXmlErrors()));
  177. }
  178. libxml_use_internal_errors($current);
  179. }
  180. /**
  181. * Retrieves libxml errors and clears them.
  182. *
  183. * @return array An array of libxml error strings
  184. */
  185. private function getXmlErrors()
  186. {
  187. $errors = array();
  188. foreach (libxml_get_errors() as $error) {
  189. $errors[] = sprintf('[%s %s] %s (in %s - line %d, column %d)',
  190. LIBXML_ERR_WARNING == $error->level ? 'WARNING' : 'ERROR',
  191. $error->code,
  192. trim($error->message),
  193. $error->file ? $error->file : 'n/a',
  194. $error->line,
  195. $error->column
  196. );
  197. }
  198. libxml_clear_errors();
  199. return $errors;
  200. }
  201. }