vendor/symfony/routing/RouteCollectionBuilder.php line 335

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;
  11. use Symfony\Component\Config\Exception\LoaderLoadException;
  12. use Symfony\Component\Config\Loader\LoaderInterface;
  13. use Symfony\Component\Config\Resource\ResourceInterface;
  14. /**
  15.  * Helps add and import routes into a RouteCollection.
  16.  *
  17.  * @author Ryan Weaver <ryan@knpuniversity.com>
  18.  */
  19. class RouteCollectionBuilder
  20. {
  21.     /**
  22.      * @var Route[]|RouteCollectionBuilder[]
  23.      */
  24.     private $routes = [];
  25.     private $loader;
  26.     private $defaults = [];
  27.     private $prefix;
  28.     private $host;
  29.     private $condition;
  30.     private $requirements = [];
  31.     private $options = [];
  32.     private $schemes;
  33.     private $methods;
  34.     private $resources = [];
  35.     public function __construct(LoaderInterface $loader null)
  36.     {
  37.         $this->loader $loader;
  38.     }
  39.     /**
  40.      * Import an external routing resource and returns the RouteCollectionBuilder.
  41.      *
  42.      *     $routes->import('blog.yml', '/blog');
  43.      *
  44.      * @param mixed $resource
  45.      *
  46.      * @return self
  47.      *
  48.      * @throws LoaderLoadException
  49.      */
  50.     public function import($resourcestring $prefix '/'string $type null)
  51.     {
  52.         /** @var RouteCollection[] $collections */
  53.         $collections $this->load($resource$type);
  54.         // create a builder from the RouteCollection
  55.         $builder $this->createBuilder();
  56.         foreach ($collections as $collection) {
  57.             if (null === $collection) {
  58.                 continue;
  59.             }
  60.             foreach ($collection->all() as $name => $route) {
  61.                 $builder->addRoute($route$name);
  62.             }
  63.             foreach ($collection->getResources() as $resource) {
  64.                 $builder->addResource($resource);
  65.             }
  66.         }
  67.         // mount into this builder
  68.         $this->mount($prefix$builder);
  69.         return $builder;
  70.     }
  71.     /**
  72.      * Adds a route and returns it for future modification.
  73.      *
  74.      * @return Route
  75.      */
  76.     public function add(string $pathstring $controllerstring $name null)
  77.     {
  78.         $route = new Route($path);
  79.         $route->setDefault('_controller'$controller);
  80.         $this->addRoute($route$name);
  81.         return $route;
  82.     }
  83.     /**
  84.      * Returns a RouteCollectionBuilder that can be configured and then added with mount().
  85.      *
  86.      * @return self
  87.      */
  88.     public function createBuilder()
  89.     {
  90.         return new self($this->loader);
  91.     }
  92.     /**
  93.      * Add a RouteCollectionBuilder.
  94.      */
  95.     public function mount(string $prefixself $builder)
  96.     {
  97.         $builder->prefix trim(trim($prefix), '/');
  98.         $this->routes[] = $builder;
  99.     }
  100.     /**
  101.      * Adds a Route object to the builder.
  102.      *
  103.      * @return $this
  104.      */
  105.     public function addRoute(Route $routestring $name null)
  106.     {
  107.         if (null === $name) {
  108.             // used as a flag to know which routes will need a name later
  109.             $name '_unnamed_route_'.spl_object_hash($route);
  110.         }
  111.         $this->routes[$name] = $route;
  112.         return $this;
  113.     }
  114.     /**
  115.      * Sets the host on all embedded routes (unless already set).
  116.      *
  117.      * @return $this
  118.      */
  119.     public function setHost(?string $pattern)
  120.     {
  121.         $this->host $pattern;
  122.         return $this;
  123.     }
  124.     /**
  125.      * Sets a condition on all embedded routes (unless already set).
  126.      *
  127.      * @return $this
  128.      */
  129.     public function setCondition(?string $condition)
  130.     {
  131.         $this->condition $condition;
  132.         return $this;
  133.     }
  134.     /**
  135.      * Sets a default value that will be added to all embedded routes (unless that
  136.      * default value is already set).
  137.      *
  138.      * @param mixed $value
  139.      *
  140.      * @return $this
  141.      */
  142.     public function setDefault(string $key$value)
  143.     {
  144.         $this->defaults[$key] = $value;
  145.         return $this;
  146.     }
  147.     /**
  148.      * Sets a requirement that will be added to all embedded routes (unless that
  149.      * requirement is already set).
  150.      *
  151.      * @param mixed $regex
  152.      *
  153.      * @return $this
  154.      */
  155.     public function setRequirement(string $key$regex)
  156.     {
  157.         $this->requirements[$key] = $regex;
  158.         return $this;
  159.     }
  160.     /**
  161.      * Sets an option that will be added to all embedded routes (unless that
  162.      * option is already set).
  163.      *
  164.      * @param mixed $value
  165.      *
  166.      * @return $this
  167.      */
  168.     public function setOption(string $key$value)
  169.     {
  170.         $this->options[$key] = $value;
  171.         return $this;
  172.     }
  173.     /**
  174.      * Sets the schemes on all embedded routes (unless already set).
  175.      *
  176.      * @param array|string $schemes
  177.      *
  178.      * @return $this
  179.      */
  180.     public function setSchemes($schemes)
  181.     {
  182.         $this->schemes $schemes;
  183.         return $this;
  184.     }
  185.     /**
  186.      * Sets the methods on all embedded routes (unless already set).
  187.      *
  188.      * @param array|string $methods
  189.      *
  190.      * @return $this
  191.      */
  192.     public function setMethods($methods)
  193.     {
  194.         $this->methods $methods;
  195.         return $this;
  196.     }
  197.     /**
  198.      * Adds a resource for this collection.
  199.      *
  200.      * @return $this
  201.      */
  202.     private function addResource(ResourceInterface $resource): self
  203.     {
  204.         $this->resources[] = $resource;
  205.         return $this;
  206.     }
  207.     /**
  208.      * Creates the final RouteCollection and returns it.
  209.      *
  210.      * @return RouteCollection
  211.      */
  212.     public function build()
  213.     {
  214.         $routeCollection = new RouteCollection();
  215.         foreach ($this->routes as $name => $route) {
  216.             if ($route instanceof Route) {
  217.                 $route->setDefaults(array_merge($this->defaults$route->getDefaults()));
  218.                 $route->setOptions(array_merge($this->options$route->getOptions()));
  219.                 foreach ($this->requirements as $key => $val) {
  220.                     if (!$route->hasRequirement($key)) {
  221.                         $route->setRequirement($key$val);
  222.                     }
  223.                 }
  224.                 if (null !== $this->prefix) {
  225.                     $route->setPath('/'.$this->prefix.$route->getPath());
  226.                 }
  227.                 if (!$route->getHost()) {
  228.                     $route->setHost($this->host);
  229.                 }
  230.                 if (!$route->getCondition()) {
  231.                     $route->setCondition($this->condition);
  232.                 }
  233.                 if (!$route->getSchemes()) {
  234.                     $route->setSchemes($this->schemes);
  235.                 }
  236.                 if (!$route->getMethods()) {
  237.                     $route->setMethods($this->methods);
  238.                 }
  239.                 // auto-generate the route name if it's been marked
  240.                 if ('_unnamed_route_' === substr($name015)) {
  241.                     $name $this->generateRouteName($route);
  242.                 }
  243.                 $routeCollection->add($name$route);
  244.             } else {
  245.                 /* @var self $route */
  246.                 $subCollection $route->build();
  247.                 if (null !== $this->prefix) {
  248.                     $subCollection->addPrefix($this->prefix);
  249.                 }
  250.                 $routeCollection->addCollection($subCollection);
  251.             }
  252.         }
  253.         foreach ($this->resources as $resource) {
  254.             $routeCollection->addResource($resource);
  255.         }
  256.         return $routeCollection;
  257.     }
  258.     /**
  259.      * Generates a route name based on details of this route.
  260.      */
  261.     private function generateRouteName(Route $route): string
  262.     {
  263.         $methods implode('_'$route->getMethods()).'_';
  264.         $routeName $methods.$route->getPath();
  265.         $routeName str_replace(['/'':''|''-'], '_'$routeName);
  266.         $routeName preg_replace('/[^a-z0-9A-Z_.]+/'''$routeName);
  267.         // Collapse consecutive underscores down into a single underscore.
  268.         $routeName preg_replace('/_+/''_'$routeName);
  269.         return $routeName;
  270.     }
  271.     /**
  272.      * Finds a loader able to load an imported resource and loads it.
  273.      *
  274.      * @param mixed       $resource A resource
  275.      * @param string|null $type     The resource type or null if unknown
  276.      *
  277.      * @return RouteCollection[]
  278.      *
  279.      * @throws LoaderLoadException If no loader is found
  280.      */
  281.     private function load($resourcestring $type null): array
  282.     {
  283.         if (null === $this->loader) {
  284.             throw new \BadMethodCallException('Cannot import other routing resources: you must pass a LoaderInterface when constructing RouteCollectionBuilder.');
  285.         }
  286.         if ($this->loader->supports($resource$type)) {
  287.             $collections $this->loader->load($resource$type);
  288.             return \is_array($collections) ? $collections : [$collections];
  289.         }
  290.         if (null === $resolver $this->loader->getResolver()) {
  291.             throw new LoaderLoadException($resourcenullnullnull$type);
  292.         }
  293.         if (false === $loader $resolver->resolve($resource$type)) {
  294.             throw new LoaderLoadException($resourcenullnullnull$type);
  295.         }
  296.         $collections $loader->load($resource$type);
  297.         return \is_array($collections) ? $collections : [$collections];
  298.     }
  299. }