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