vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php line 56

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\Bundle\FrameworkBundle\Routing;
  11. use Symfony\Component\Config\Loader\LoaderInterface;
  12. use Symfony\Component\DependencyInjection\Config\ContainerParametersResource;
  13. use Symfony\Component\DependencyInjection\ContainerInterface;
  14. use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
  15. use Symfony\Component\DependencyInjection\Exception\RuntimeException;
  16. use Symfony\Component\DependencyInjection\ServiceSubscriberInterface;
  17. use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface;
  18. use Symfony\Component\Routing\RequestContext;
  19. use Symfony\Component\Routing\RouteCollection;
  20. use Symfony\Component\Routing\Router as BaseRouter;
  21. /**
  22.  * This Router creates the Loader only when the cache is empty.
  23.  *
  24.  * @author Fabien Potencier <fabien@symfony.com>
  25.  */
  26. class Router extends BaseRouter implements WarmableInterfaceServiceSubscriberInterface
  27. {
  28.     private $container;
  29.     private $collectedParameters = [];
  30.     /**
  31.      * @param ContainerInterface $container A ContainerInterface instance
  32.      * @param mixed              $resource  The main resource to load
  33.      * @param array              $options   An array of options
  34.      * @param RequestContext     $context   The context
  35.      */
  36.     public function __construct(ContainerInterface $container$resource, array $options = [], RequestContext $context null)
  37.     {
  38.         $this->container $container;
  39.         $this->resource $resource;
  40.         $this->context $context ?: new RequestContext();
  41.         $this->setOptions($options);
  42.     }
  43.     /**
  44.      * {@inheritdoc}
  45.      */
  46.     public function getRouteCollection()
  47.     {
  48.         if (null === $this->collection) {
  49.             $this->collection $this->container->get('routing.loader')->load($this->resource$this->options['resource_type']);
  50.             $this->resolveParameters($this->collection);
  51.             $this->collection->addResource(new ContainerParametersResource($this->collectedParameters));
  52.         }
  53.         return $this->collection;
  54.     }
  55.     /**
  56.      * {@inheritdoc}
  57.      */
  58.     public function warmUp($cacheDir)
  59.     {
  60.         $currentDir $this->getOption('cache_dir');
  61.         // force cache generation
  62.         $this->setOption('cache_dir'$cacheDir);
  63.         $this->getMatcher();
  64.         $this->getGenerator();
  65.         $this->setOption('cache_dir'$currentDir);
  66.     }
  67.     /**
  68.      * Replaces placeholders with service container parameter values in:
  69.      * - the route defaults,
  70.      * - the route requirements,
  71.      * - the route path,
  72.      * - the route host,
  73.      * - the route schemes,
  74.      * - the route methods.
  75.      */
  76.     private function resolveParameters(RouteCollection $collection)
  77.     {
  78.         foreach ($collection as $route) {
  79.             foreach ($route->getDefaults() as $name => $value) {
  80.                 $route->setDefault($name$this->resolve($value));
  81.             }
  82.             foreach ($route->getRequirements() as $name => $value) {
  83.                 $route->setRequirement($name$this->resolve($value));
  84.             }
  85.             $route->setPath($this->resolve($route->getPath()));
  86.             $route->setHost($this->resolve($route->getHost()));
  87.             $schemes = [];
  88.             foreach ($route->getSchemes() as $scheme) {
  89.                 $schemes array_merge($schemesexplode('|'$this->resolve($scheme)));
  90.             }
  91.             $route->setSchemes($schemes);
  92.             $methods = [];
  93.             foreach ($route->getMethods() as $method) {
  94.                 $methods array_merge($methodsexplode('|'$this->resolve($method)));
  95.             }
  96.             $route->setMethods($methods);
  97.             $route->setCondition($this->resolve($route->getCondition()));
  98.         }
  99.     }
  100.     /**
  101.      * Recursively replaces placeholders with the service container parameters.
  102.      *
  103.      * @param mixed $value The source which might contain "%placeholders%"
  104.      *
  105.      * @return mixed The source with the placeholders replaced by the container
  106.      *               parameters. Arrays are resolved recursively.
  107.      *
  108.      * @throws ParameterNotFoundException When a placeholder does not exist as a container parameter
  109.      * @throws RuntimeException           When a container value is not a string or a numeric value
  110.      */
  111.     private function resolve($value)
  112.     {
  113.         if (\is_array($value)) {
  114.             foreach ($value as $key => $val) {
  115.                 $value[$key] = $this->resolve($val);
  116.             }
  117.             return $value;
  118.         }
  119.         if (!\is_string($value)) {
  120.             return $value;
  121.         }
  122.         $container $this->container;
  123.         $escapedValue preg_replace_callback('/%%|%([^%\s]++)%/', function ($match) use ($container$value) {
  124.             // skip %%
  125.             if (!isset($match[1])) {
  126.                 return '%%';
  127.             }
  128.             if (preg_match('/^env\((?:\w++:)*+\w++\)$/'$match[1])) {
  129.                 throw new RuntimeException(sprintf('Using "%%%s%%" is not allowed in routing configuration.'$match[1]));
  130.             }
  131.             $resolved $container->getParameter($match[1]);
  132.             if (\is_string($resolved) || is_numeric($resolved)) {
  133.                 $this->collectedParameters[$match[1]] = $resolved;
  134.                 return (string) $this->resolve($resolved);
  135.             }
  136.             throw new RuntimeException(sprintf('The container parameter "%s", used in the route configuration value "%s", must be a string or numeric, but it is of type "%s".'$match[1], $value, \gettype($resolved)));
  137.         }, $value);
  138.         return str_replace('%%''%'$escapedValue);
  139.     }
  140.     /**
  141.      * {@inheritdoc}
  142.      */
  143.     public static function getSubscribedServices()
  144.     {
  145.         return [
  146.             'routing.loader' => LoaderInterface::class,
  147.         ];
  148.     }
  149. }