Blame | Last modification | View Log | RSS feed
<?php/** This file is part of the Symfony package.** (c) Fabien Potencier <fabien@symfony.com>** For the full copyright and license information, please view the LICENSE* file that was distributed with this source code.*/namespace Symfony\Component\Routing\Loader;use Symfony\Component\Config\Loader\FileLoader;use Symfony\Component\Config\Resource\FileResource;use Symfony\Component\Routing\Loader\Configurator\Traits\HostTrait;use Symfony\Component\Routing\Loader\Configurator\Traits\LocalizedRouteTrait;use Symfony\Component\Routing\Loader\Configurator\Traits\PrefixTrait;use Symfony\Component\Routing\RouteCollection;use Symfony\Component\Yaml\Exception\ParseException;use Symfony\Component\Yaml\Parser as YamlParser;use Symfony\Component\Yaml\Yaml;/*** YamlFileLoader loads Yaml routing files.** @author Fabien Potencier <fabien@symfony.com>* @author Tobias Schultze <http://tobion.de>*/class YamlFileLoader extends FileLoader{use HostTrait;use LocalizedRouteTrait;use PrefixTrait;private static $availableKeys = ['resource', 'type', 'prefix', 'path', 'host', 'schemes', 'methods', 'defaults', 'requirements', 'options', 'condition', 'controller', 'name_prefix', 'trailing_slash_on_root', 'locale', 'format', 'utf8', 'exclude', 'stateless',];private $yamlParser;/*** Loads a Yaml file.** @param string $file A Yaml file path* @param string|null $type The resource type** @return RouteCollection A RouteCollection instance** @throws \InvalidArgumentException When a route can't be parsed because YAML is invalid*/public function load($file, string $type = null){$path = $this->locator->locate($file);if (!stream_is_local($path)) {throw new \InvalidArgumentException(sprintf('This is not a local file "%s".', $path));}if (!file_exists($path)) {throw new \InvalidArgumentException(sprintf('File "%s" not found.', $path));}if (null === $this->yamlParser) {$this->yamlParser = new YamlParser();}try {$parsedConfig = $this->yamlParser->parseFile($path, Yaml::PARSE_CONSTANT);} catch (ParseException $e) {throw new \InvalidArgumentException(sprintf('The file "%s" does not contain valid YAML: ', $path).$e->getMessage(), 0, $e);}$collection = new RouteCollection();$collection->addResource(new FileResource($path));// empty fileif (null === $parsedConfig) {return $collection;}// not an arrayif (!\is_array($parsedConfig)) {throw new \InvalidArgumentException(sprintf('The file "%s" must contain a YAML array.', $path));}foreach ($parsedConfig as $name => $config) {$this->validate($config, $name, $path);if (isset($config['resource'])) {$this->parseImport($collection, $config, $path, $file);} else {$this->parseRoute($collection, $name, $config, $path);}}return $collection;}/*** {@inheritdoc}*/public function supports($resource, string $type = null){return \is_string($resource) && \in_array(pathinfo($resource, \PATHINFO_EXTENSION), ['yml', 'yaml'], true) && (!$type || 'yaml' === $type);}/*** Parses a route and adds it to the RouteCollection.** @param string $name Route name* @param array $config Route definition* @param string $path Full path of the YAML file being processed*/protected function parseRoute(RouteCollection $collection, string $name, array $config, string $path){$defaults = isset($config['defaults']) ? $config['defaults'] : [];$requirements = isset($config['requirements']) ? $config['requirements'] : [];$options = isset($config['options']) ? $config['options'] : [];foreach ($requirements as $placeholder => $requirement) {if (\is_int($placeholder)) {throw new \InvalidArgumentException(sprintf('A placeholder name must be a string (%d given). Did you forget to specify the placeholder key for the requirement "%s" of route "%s" in "%s"?', $placeholder, $requirement, $name, $path));}}if (isset($config['controller'])) {$defaults['_controller'] = $config['controller'];}if (isset($config['locale'])) {$defaults['_locale'] = $config['locale'];}if (isset($config['format'])) {$defaults['_format'] = $config['format'];}if (isset($config['utf8'])) {$options['utf8'] = $config['utf8'];}if (isset($config['stateless'])) {$defaults['_stateless'] = $config['stateless'];}$routes = $this->createLocalizedRoute($collection, $name, $config['path']);$routes->addDefaults($defaults);$routes->addRequirements($requirements);$routes->addOptions($options);$routes->setSchemes($config['schemes'] ?? []);$routes->setMethods($config['methods'] ?? []);$routes->setCondition($config['condition'] ?? null);if (isset($config['host'])) {$this->addHost($routes, $config['host']);}}/*** Parses an import and adds the routes in the resource to the RouteCollection.** @param array $config Route definition* @param string $path Full path of the YAML file being processed* @param string $file Loaded file name*/protected function parseImport(RouteCollection $collection, array $config, string $path, string $file){$type = isset($config['type']) ? $config['type'] : null;$prefix = isset($config['prefix']) ? $config['prefix'] : '';$defaults = isset($config['defaults']) ? $config['defaults'] : [];$requirements = isset($config['requirements']) ? $config['requirements'] : [];$options = isset($config['options']) ? $config['options'] : [];$host = isset($config['host']) ? $config['host'] : null;$condition = isset($config['condition']) ? $config['condition'] : null;$schemes = isset($config['schemes']) ? $config['schemes'] : null;$methods = isset($config['methods']) ? $config['methods'] : null;$trailingSlashOnRoot = $config['trailing_slash_on_root'] ?? true;$namePrefix = $config['name_prefix'] ?? null;$exclude = $config['exclude'] ?? null;if (isset($config['controller'])) {$defaults['_controller'] = $config['controller'];}if (isset($config['locale'])) {$defaults['_locale'] = $config['locale'];}if (isset($config['format'])) {$defaults['_format'] = $config['format'];}if (isset($config['utf8'])) {$options['utf8'] = $config['utf8'];}if (isset($config['stateless'])) {$defaults['_stateless'] = $config['stateless'];}$this->setCurrentDir(\dirname($path));/** @var RouteCollection[] $imported */$imported = $this->import($config['resource'], $type, false, $file, $exclude) ?: [];if (!\is_array($imported)) {$imported = [$imported];}foreach ($imported as $subCollection) {$this->addPrefix($subCollection, $prefix, $trailingSlashOnRoot);if (null !== $host) {$this->addHost($subCollection, $host);}if (null !== $condition) {$subCollection->setCondition($condition);}if (null !== $schemes) {$subCollection->setSchemes($schemes);}if (null !== $methods) {$subCollection->setMethods($methods);}if (null !== $namePrefix) {$subCollection->addNamePrefix($namePrefix);}$subCollection->addDefaults($defaults);$subCollection->addRequirements($requirements);$subCollection->addOptions($options);$collection->addCollection($subCollection);}}/*** Validates the route configuration.** @param array $config A resource config* @param string $name The config key* @param string $path The loaded file path** @throws \InvalidArgumentException If one of the provided config keys is not supported,* something is missing or the combination is nonsense*/protected function validate($config, string $name, string $path){if (!\is_array($config)) {throw new \InvalidArgumentException(sprintf('The definition of "%s" in "%s" must be a YAML array.', $name, $path));}if ($extraKeys = array_diff(array_keys($config), self::$availableKeys)) {throw new \InvalidArgumentException(sprintf('The routing file "%s" contains unsupported keys for "%s": "%s". Expected one of: "%s".', $path, $name, implode('", "', $extraKeys), implode('", "', self::$availableKeys)));}if (isset($config['resource']) && isset($config['path'])) {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));}if (!isset($config['resource']) && isset($config['type'])) {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));}if (!isset($config['resource']) && !isset($config['path'])) {throw new \InvalidArgumentException(sprintf('You must define a "path" for the route "%s" in file "%s".', $name, $path));}if (isset($config['controller']) && isset($config['defaults']['_controller'])) {throw new \InvalidArgumentException(sprintf('The routing file "%s" must not specify both the "controller" key and the defaults key "_controller" for "%s".', $path, $name));}if (isset($config['stateless']) && isset($config['defaults']['_stateless'])) {throw new \InvalidArgumentException(sprintf('The routing file "%s" must not specify both the "stateless" key and the defaults key "_stateless" for "%s".', $path, $name));}}}