vendor/symfony/routing/RouteCollectionBuilder.php line 373

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