vendor/symfony/routing/RouteCollectionBuilder.php line 372

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