2016-04-20 09:56:34 -07:00
< ? 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 ;
use Symfony\Component\Config\Exception\FileLoaderLoadException ;
use Symfony\Component\Config\Loader\LoaderInterface ;
use Symfony\Component\Config\Resource\ResourceInterface ;
/**
* Helps add and import routes into a RouteCollection .
*
* @ author Ryan Weaver < ryan @ knpuniversity . com >
*/
class RouteCollectionBuilder
{
/**
* @ var Route [] | RouteCollectionBuilder []
*/
private $routes = array ();
private $loader ;
private $defaults = array ();
private $prefix ;
private $host ;
private $condition ;
private $requirements = array ();
private $options = array ();
private $schemes ;
private $methods ;
private $resources = array ();
/**
* @ param LoaderInterface $loader
*/
public function __construct ( LoaderInterface $loader = null )
{
$this -> loader = $loader ;
}
/**
* Import an external routing resource and returns the RouteCollectionBuilder .
*
* $routes -> import ( 'blog.yml' , '/blog' );
*
* @ param mixed $resource
* @ param string | null $prefix
* @ param string $type
*
2017-02-02 16:28:38 -08:00
* @ return self
2016-04-20 09:56:34 -07:00
*
* @ throws FileLoaderLoadException
*/
public function import ( $resource , $prefix = '/' , $type = null )
{
/** @var RouteCollection $collection */
$collection = $this -> load ( $resource , $type );
// create a builder from the RouteCollection
$builder = $this -> createBuilder ();
foreach ( $collection -> all () as $name => $route ) {
$builder -> addRoute ( $route , $name );
}
foreach ( $collection -> getResources () as $resource ) {
$builder -> addResource ( $resource );
}
// mount into this builder
$this -> mount ( $prefix , $builder );
return $builder ;
}
/**
* Adds a route and returns it for future modification .
*
* @ param string $path The route path
* @ param string $controller The route ' s controller
* @ param string | null $name The name to give this route
*
* @ return Route
*/
public function add ( $path , $controller , $name = null )
{
$route = new Route ( $path );
$route -> setDefault ( '_controller' , $controller );
$this -> addRoute ( $route , $name );
return $route ;
}
/**
* Returns a RouteCollectionBuilder that can be configured and then added with mount () .
*
2017-02-02 16:28:38 -08:00
* @ return self
2016-04-20 09:56:34 -07:00
*/
public function createBuilder ()
{
return new self ( $this -> loader );
}
/**
* Add a RouteCollectionBuilder .
*
* @ param string $prefix
* @ param RouteCollectionBuilder $builder
*/
public function mount ( $prefix , RouteCollectionBuilder $builder )
{
$builder -> prefix = trim ( trim ( $prefix ), '/' );
$this -> routes [] = $builder ;
}
/**
* Adds a Route object to the builder .
*
* @ param Route $route
* @ param string | null $name
*
* @ return $this
*/
public function addRoute ( Route $route , $name = null )
{
if ( null === $name ) {
// used as a flag to know which routes will need a name later
$name = '_unnamed_route_' . spl_object_hash ( $route );
}
$this -> routes [ $name ] = $route ;
return $this ;
}
/**
* Sets the host on all embedded routes ( unless already set ) .
*
* @ param string $pattern
*
* @ return $this
*/
public function setHost ( $pattern )
{
$this -> host = $pattern ;
return $this ;
}
/**
* Sets a condition on all embedded routes ( unless already set ) .
*
* @ param string $condition
*
* @ return $this
*/
public function setCondition ( $condition )
{
$this -> condition = $condition ;
return $this ;
}
/**
* Sets a default value that will be added to all embedded routes ( unless that
2017-02-02 16:28:38 -08:00
* default value is already set ) .
2016-04-20 09:56:34 -07:00
*
* @ param string $key
* @ param mixed $value
*
* @ return $this
*/
public function setDefault ( $key , $value )
{
$this -> defaults [ $key ] = $value ;
return $this ;
}
/**
* Sets a requirement that will be added to all embedded routes ( unless that
2017-02-02 16:28:38 -08:00
* requirement is already set ) .
2016-04-20 09:56:34 -07:00
*
* @ param string $key
* @ param mixed $regex
*
* @ return $this
*/
public function setRequirement ( $key , $regex )
{
$this -> requirements [ $key ] = $regex ;
return $this ;
}
/**
* Sets an opiton that will be added to all embedded routes ( unless that
2017-02-02 16:28:38 -08:00
* option is already set ) .
2016-04-20 09:56:34 -07:00
*
* @ param string $key
* @ param mixed $value
*
* @ return $this
*/
public function setOption ( $key , $value )
{
$this -> options [ $key ] = $value ;
return $this ;
}
/**
* Sets the schemes on all embedded routes ( unless already set ) .
*
* @ param array | string $schemes
*
* @ return $this
*/
public function setSchemes ( $schemes )
{
$this -> schemes = $schemes ;
return $this ;
}
/**
* Sets the methods on all embedded routes ( unless already set ) .
*
* @ param array | string $methods
*
* @ return $this
*/
public function setMethods ( $methods )
{
$this -> methods = $methods ;
return $this ;
}
/**
* Adds a resource for this collection .
*
* @ param ResourceInterface $resource
*
* @ return $this
*/
private function addResource ( ResourceInterface $resource )
{
$this -> resources [] = $resource ;
return $this ;
}
/**
* Creates the final RouteCollection and returns it .
*
* @ return RouteCollection
*/
public function build ()
{
$routeCollection = new RouteCollection ();
foreach ( $this -> routes as $name => $route ) {
if ( $route instanceof Route ) {
$route -> setDefaults ( array_merge ( $this -> defaults , $route -> getDefaults ()));
$route -> setOptions ( array_merge ( $this -> options , $route -> getOptions ()));
// we're extra careful here to avoid re-setting deprecated _method and _scheme
foreach ( $this -> requirements as $key => $val ) {
if ( ! $route -> hasRequirement ( $key )) {
$route -> setRequirement ( $key , $val );
}
}
if ( null !== $this -> prefix ) {
$route -> setPath ( '/' . $this -> prefix . $route -> getPath ());
}
if ( ! $route -> getHost ()) {
$route -> setHost ( $this -> host );
}
if ( ! $route -> getCondition ()) {
$route -> setCondition ( $this -> condition );
}
if ( ! $route -> getSchemes ()) {
$route -> setSchemes ( $this -> schemes );
}
if ( ! $route -> getMethods ()) {
$route -> setMethods ( $this -> methods );
}
// auto-generate the route name if it's been marked
if ( '_unnamed_route_' === substr ( $name , 0 , 15 )) {
$name = $this -> generateRouteName ( $route );
}
$routeCollection -> add ( $name , $route );
} else {
/* @var self $route */
$subCollection = $route -> build ();
$subCollection -> addPrefix ( $this -> prefix );
$routeCollection -> addCollection ( $subCollection );
}
foreach ( $this -> resources as $resource ) {
$routeCollection -> addResource ( $resource );
}
}
return $routeCollection ;
}
/**
* Generates a route name based on details of this route .
*
* @ return string
*/
private function generateRouteName ( Route $route )
{
$methods = implode ( '_' , $route -> getMethods ()) . '_' ;
$routeName = $methods . $route -> getPath ();
$routeName = str_replace ( array ( '/' , ':' , '|' , '-' ), '_' , $routeName );
$routeName = preg_replace ( '/[^a-z0-9A-Z_.]+/' , '' , $routeName );
// Collapse consecutive underscores down into a single underscore.
$routeName = preg_replace ( '/_+/' , '_' , $routeName );
return $routeName ;
}
/**
* Finds a loader able to load an imported resource and loads it .
*
* @ param mixed $resource A resource
* @ param string | null $type The resource type or null if unknown
*
* @ return RouteCollection
*
* @ throws FileLoaderLoadException If no loader is found
*/
private function load ( $resource , $type = null )
{
if ( null === $this -> loader ) {
throw new \BadMethodCallException ( 'Cannot import other routing resources: you must pass a LoaderInterface when constructing RouteCollectionBuilder.' );
}
if ( $this -> loader -> supports ( $resource , $type )) {
return $this -> loader -> load ( $resource , $type );
}
if ( null === $resolver = $this -> loader -> getResolver ()) {
throw new FileLoaderLoadException ( $resource );
}
if ( false === $loader = $resolver -> resolve ( $resource , $type )) {
throw new FileLoaderLoadException ( $resource );
}
return $loader -> load ( $resource , $type );
}
}