vendor/symfony/symfony/src/Symfony/Component/Routing/Loader/YamlFileLoader.php line 161

Open in your IDE?
  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\Config\Loader\FileLoader;
  12. use Symfony\Component\Config\Resource\FileResource;
  13. use Symfony\Component\Routing\Route;
  14. use Symfony\Component\Routing\RouteCollection;
  15. use Symfony\Component\Yaml\Exception\ParseException;
  16. use Symfony\Component\Yaml\Parser as YamlParser;
  17. /**
  18.  * YamlFileLoader loads Yaml routing files.
  19.  *
  20.  * @author Fabien Potencier <fabien@symfony.com>
  21.  * @author Tobias Schultze <http://tobion.de>
  22.  */
  23. class YamlFileLoader extends FileLoader
  24. {
  25.     private static $availableKeys = [
  26.         'resource''type''prefix''path''host''schemes''methods''defaults''requirements''options''condition''controller',
  27.     ];
  28.     private $yamlParser;
  29.     /**
  30.      * Loads a Yaml file.
  31.      *
  32.      * @param string      $file A Yaml file path
  33.      * @param string|null $type The resource type
  34.      *
  35.      * @return RouteCollection A RouteCollection instance
  36.      *
  37.      * @throws \InvalidArgumentException When a route can't be parsed because YAML is invalid
  38.      */
  39.     public function load($file$type null)
  40.     {
  41.         $path $this->locator->locate($file);
  42.         if (!stream_is_local($path)) {
  43.             throw new \InvalidArgumentException(sprintf('This is not a local file "%s".'$path));
  44.         }
  45.         if (!file_exists($path)) {
  46.             throw new \InvalidArgumentException(sprintf('File "%s" not found.'$path));
  47.         }
  48.         if (null === $this->yamlParser) {
  49.             $this->yamlParser = new YamlParser();
  50.         }
  51.         $prevErrorHandler set_error_handler(function ($level$message$script$line) use ($file, &$prevErrorHandler) {
  52.             $message E_USER_DEPRECATED === $level preg_replace('/ on line \d+/'' in "'.$file.'"$0'$message) : $message;
  53.             return $prevErrorHandler $prevErrorHandler($level$message$script$line) : false;
  54.         });
  55.         try {
  56.             $parsedConfig $this->yamlParser->parseFile($path);
  57.         } catch (ParseException $e) {
  58.             throw new \InvalidArgumentException(sprintf('The file "%s" does not contain valid YAML.'$path), 0$e);
  59.         } finally {
  60.             restore_error_handler();
  61.         }
  62.         $collection = new RouteCollection();
  63.         $collection->addResource(new FileResource($path));
  64.         // empty file
  65.         if (null === $parsedConfig) {
  66.             return $collection;
  67.         }
  68.         // not an array
  69.         if (!\is_array($parsedConfig)) {
  70.             throw new \InvalidArgumentException(sprintf('The file "%s" must contain a YAML array.'$path));
  71.         }
  72.         foreach ($parsedConfig as $name => $config) {
  73.             $this->validate($config$name$path);
  74.             if (isset($config['resource'])) {
  75.                 $this->parseImport($collection$config$path$file);
  76.             } else {
  77.                 $this->parseRoute($collection$name$config$path);
  78.             }
  79.         }
  80.         return $collection;
  81.     }
  82.     /**
  83.      * {@inheritdoc}
  84.      */
  85.     public function supports($resource$type null)
  86.     {
  87.         return \is_string($resource) && \in_array(pathinfo($resourcePATHINFO_EXTENSION), ['yml''yaml'], true) && (!$type || 'yaml' === $type);
  88.     }
  89.     /**
  90.      * Parses a route and adds it to the RouteCollection.
  91.      *
  92.      * @param RouteCollection $collection A RouteCollection instance
  93.      * @param string          $name       Route name
  94.      * @param array           $config     Route definition
  95.      * @param string          $path       Full path of the YAML file being processed
  96.      */
  97.     protected function parseRoute(RouteCollection $collection$name, array $config$path)
  98.     {
  99.         $defaults = isset($config['defaults']) ? $config['defaults'] : [];
  100.         $requirements = isset($config['requirements']) ? $config['requirements'] : [];
  101.         $options = isset($config['options']) ? $config['options'] : [];
  102.         $host = isset($config['host']) ? $config['host'] : '';
  103.         $schemes = isset($config['schemes']) ? $config['schemes'] : [];
  104.         $methods = isset($config['methods']) ? $config['methods'] : [];
  105.         $condition = isset($config['condition']) ? $config['condition'] : null;
  106.         if (isset($config['controller'])) {
  107.             $defaults['_controller'] = $config['controller'];
  108.         }
  109.         $route = new Route($config['path'], $defaults$requirements$options$host$schemes$methods$condition);
  110.         $collection->add($name$route);
  111.     }
  112.     /**
  113.      * Parses an import and adds the routes in the resource to the RouteCollection.
  114.      *
  115.      * @param RouteCollection $collection A RouteCollection instance
  116.      * @param array           $config     Route definition
  117.      * @param string          $path       Full path of the YAML file being processed
  118.      * @param string          $file       Loaded file name
  119.      */
  120.     protected function parseImport(RouteCollection $collection, array $config$path$file)
  121.     {
  122.         $type = isset($config['type']) ? $config['type'] : null;
  123.         $prefix = isset($config['prefix']) ? $config['prefix'] : '';
  124.         $defaults = isset($config['defaults']) ? $config['defaults'] : [];
  125.         $requirements = isset($config['requirements']) ? $config['requirements'] : [];
  126.         $options = isset($config['options']) ? $config['options'] : [];
  127.         $host = isset($config['host']) ? $config['host'] : null;
  128.         $condition = isset($config['condition']) ? $config['condition'] : null;
  129.         $schemes = isset($config['schemes']) ? $config['schemes'] : null;
  130.         $methods = isset($config['methods']) ? $config['methods'] : null;
  131.         if (isset($config['controller'])) {
  132.             $defaults['_controller'] = $config['controller'];
  133.         }
  134.         $this->setCurrentDir(\dirname($path));
  135.         $imported $this->import($config['resource'], $typefalse$file) ?: [];
  136.         if (!\is_array($imported)) {
  137.             $imported = [$imported];
  138.         }
  139.         foreach ($imported as $subCollection) {
  140.             /* @var $subCollection RouteCollection */
  141.             $subCollection->addPrefix($prefix);
  142.             if (null !== $host) {
  143.                 $subCollection->setHost($host);
  144.             }
  145.             if (null !== $condition) {
  146.                 $subCollection->setCondition($condition);
  147.             }
  148.             if (null !== $schemes) {
  149.                 $subCollection->setSchemes($schemes);
  150.             }
  151.             if (null !== $methods) {
  152.                 $subCollection->setMethods($methods);
  153.             }
  154.             $subCollection->addDefaults($defaults);
  155.             $subCollection->addRequirements($requirements);
  156.             $subCollection->addOptions($options);
  157.             $collection->addCollection($subCollection);
  158.         }
  159.     }
  160.     /**
  161.      * Validates the route configuration.
  162.      *
  163.      * @param array  $config A resource config
  164.      * @param string $name   The config key
  165.      * @param string $path   The loaded file path
  166.      *
  167.      * @throws \InvalidArgumentException If one of the provided config keys is not supported,
  168.      *                                   something is missing or the combination is nonsense
  169.      */
  170.     protected function validate($config$name$path)
  171.     {
  172.         if (!\is_array($config)) {
  173.             throw new \InvalidArgumentException(sprintf('The definition of "%s" in "%s" must be a YAML array.'$name$path));
  174.         }
  175.         if ($extraKeys array_diff(array_keys($config), self::$availableKeys)) {
  176.             throw new \InvalidArgumentException(sprintf('The routing file "%s" contains unsupported keys for "%s": "%s". Expected one of: "%s".'$path$nameimplode('", "'$extraKeys), implode('", "'self::$availableKeys)));
  177.         }
  178.         if (isset($config['resource']) && isset($config['path'])) {
  179.             throw new \InvalidArgumentException(sprintf('The routing file "%s" must not specify both the "resource" key and the "path" key for "%s". Choose between an import and a route definition.'$path$name));
  180.         }
  181.         if (!isset($config['resource']) && isset($config['type'])) {
  182.             throw new \InvalidArgumentException(sprintf('The "type" key for the route definition "%s" in "%s" is unsupported. It is only available for imports in combination with the "resource" key.'$name$path));
  183.         }
  184.         if (!isset($config['resource']) && !isset($config['path'])) {
  185.             throw new \InvalidArgumentException(sprintf('You must define a "path" for the route "%s" in file "%s".'$name$path));
  186.         }
  187.         if (isset($config['controller']) && isset($config['defaults']['_controller'])) {
  188.             throw new \InvalidArgumentException(sprintf('The routing file "%s" must not specify both the "controller" key and the defaults key "_controller" for "%s".'$path$name));
  189.         }
  190.     }
  191. }