2011-06-07 10:36:32 +01: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\Bundle\FrameworkBundle\Routing ;
2017-10-29 08:23:24 +00:00
use Psr\Container\ContainerInterface ;
2017-11-05 16:04:27 +00:00
use Psr\Log\LoggerInterface ;
2017-03-10 18:38:01 +00:00
use Symfony\Component\Config\Loader\LoaderInterface ;
2017-02-22 23:13:41 +00:00
use Symfony\Component\DependencyInjection\Config\ContainerParametersResource ;
2017-10-29 08:23:24 +00:00
use Symfony\Component\DependencyInjection\ContainerInterface as SymfonyContainerInterface ;
2017-03-10 18:38:01 +00:00
use Symfony\Component\DependencyInjection\ServiceSubscriberInterface ;
2011-06-07 10:36:32 +01:00
use Symfony\Component\Routing\Router as BaseRouter ;
use Symfony\Component\Routing\RequestContext ;
2011-09-14 07:48:23 +01:00
use Symfony\Component\Routing\RouteCollection ;
2011-10-23 08:46:33 +01:00
use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface ;
2012-07-04 13:24:46 +01:00
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException ;
use Symfony\Component\DependencyInjection\Exception\RuntimeException ;
2011-06-07 10:36:32 +01:00
/**
2012-07-31 14:07:47 +01:00
* This Router creates the Loader only when the cache is empty .
2011-06-07 10:36:32 +01:00
*
* @ author Fabien Potencier < fabien @ symfony . com >
*/
2017-03-10 18:38:01 +00:00
class Router extends BaseRouter implements WarmableInterface , ServiceSubscriberInterface
2011-06-07 10:36:32 +01:00
{
private $container ;
2017-02-22 23:13:41 +00:00
private $collectedParameters = array ();
2017-10-29 08:23:24 +00:00
private $paramFetcher ;
2011-06-07 10:36:32 +01:00
/**
2017-10-29 08:23:24 +00:00
* @ param ContainerInterface $container A ContainerInterface instance
* @ param mixed $resource The main resource to load
* @ param array $options An array of options
* @ param RequestContext $context The context
* @ param ContainerInterface | null $parameters A ContainerInterface instance allowing to fetch parameters
* @ param LoggerInterface | null $logger
2011-06-07 10:36:32 +01:00
*/
2017-10-29 08:23:24 +00:00
public function __construct ( ContainerInterface $container , $resource , array $options = array (), RequestContext $context = null , ContainerInterface $parameters = null , LoggerInterface $logger = null )
2011-06-07 10:36:32 +01:00
{
$this -> container = $container ;
$this -> resource = $resource ;
2013-11-14 14:22:38 +00:00
$this -> context = $context ? : new RequestContext ();
2017-11-05 16:04:27 +00:00
$this -> logger = $logger ;
2011-06-07 10:36:32 +01:00
$this -> setOptions ( $options );
2017-10-29 08:23:24 +00:00
if ( $parameters ) {
$this -> paramFetcher = array ( $parameters , 'get' );
} elseif ( $container instanceof SymfonyContainerInterface ) {
$this -> paramFetcher = array ( $container , 'getParameter' );
} else {
throw new \LogicException ( sprintf ( 'You should either pass a "%s" instance or provide the $parameters argument of the "%s" method.' , SymfonyContainerInterface :: class , __METHOD__ ));
}
2011-06-07 10:36:32 +01:00
}
/**
2011-09-28 08:00:17 +01:00
* { @ inheritdoc }
2011-06-07 10:36:32 +01:00
*/
public function getRouteCollection ()
{
if ( null === $this -> collection ) {
$this -> collection = $this -> container -> get ( 'routing.loader' ) -> load ( $this -> resource , $this -> options [ 'resource_type' ]);
2011-09-14 08:19:55 +01:00
$this -> resolveParameters ( $this -> collection );
2017-02-22 23:13:41 +00:00
$this -> collection -> addResource ( new ContainerParametersResource ( $this -> collectedParameters ));
2011-06-07 10:36:32 +01:00
}
return $this -> collection ;
}
2011-08-10 12:34:58 +01:00
2011-10-22 15:11:56 +01:00
/**
* { @ inheritdoc }
*/
public function warmUp ( $cacheDir )
{
$currentDir = $this -> getOption ( 'cache_dir' );
// force cache generation
$this -> setOption ( 'cache_dir' , $cacheDir );
$this -> getMatcher ();
$this -> getGenerator ();
$this -> setOption ( 'cache_dir' , $currentDir );
}
2011-08-10 12:34:58 +01:00
/**
2012-07-04 13:24:46 +01:00
* Replaces placeholders with service container parameter values in :
* - the route defaults ,
* - the route requirements ,
2015-01-12 18:11:00 +00:00
* - the route path ,
* - the route host ,
* - the route schemes ,
* - the route methods .
2011-08-10 12:34:58 +01:00
*/
2011-09-14 08:19:55 +01:00
private function resolveParameters ( RouteCollection $collection )
2011-08-10 12:34:58 +01:00
{
2011-09-14 07:48:23 +01:00
foreach ( $collection as $route ) {
2012-11-26 17:28:37 +00:00
foreach ( $route -> getDefaults () as $name => $value ) {
$route -> setDefault ( $name , $this -> resolve ( $value ));
2011-08-10 12:34:58 +01:00
}
2012-11-26 17:28:37 +00:00
foreach ( $route -> getRequirements () as $name => $value ) {
2014-09-21 19:53:12 +01:00
$route -> setRequirement ( $name , $this -> resolve ( $value ));
2012-11-26 17:28:37 +00:00
}
2013-01-16 22:04:10 +00:00
$route -> setPath ( $this -> resolve ( $route -> getPath ()));
2013-01-21 16:57:28 +00:00
$route -> setHost ( $this -> resolve ( $route -> getHost ()));
2015-01-12 18:11:00 +00:00
$schemes = array ();
foreach ( $route -> getSchemes () as $scheme ) {
$schemes = array_merge ( $schemes , explode ( '|' , $this -> resolve ( $scheme )));
}
$route -> setSchemes ( $schemes );
$methods = array ();
foreach ( $route -> getMethods () as $method ) {
$methods = array_merge ( $methods , explode ( '|' , $this -> resolve ( $method )));
}
$route -> setMethods ( $methods );
2014-12-12 15:28:54 +00:00
$route -> setCondition ( $this -> resolve ( $route -> getCondition ()));
2011-08-10 12:34:58 +01:00
}
}
2012-07-04 13:24:46 +01:00
/**
2012-11-10 16:18:12 +00:00
* Recursively replaces placeholders with the service container parameters .
2012-07-04 13:24:46 +01:00
*
2012-11-10 16:18:12 +00:00
* @ param mixed $value The source which might contain " %placeholders% "
2012-07-04 13:24:46 +01:00
*
2012-11-10 16:18:12 +00:00
* @ return mixed The source with the placeholders replaced by the container
2013-10-24 17:39:19 +01:00
* parameters . Arrays are resolved recursively .
2012-07-04 13:24:46 +01:00
*
* @ throws ParameterNotFoundException When a placeholder does not exist as a container parameter
* @ throws RuntimeException When a container value is not a string or a numeric value
*/
2012-11-10 16:18:12 +00:00
private function resolve ( $value )
2012-07-04 13:24:46 +01:00
{
2012-07-20 13:59:54 +01:00
if ( is_array ( $value )) {
foreach ( $value as $key => $val ) {
2012-11-10 16:18:12 +00:00
$value [ $key ] = $this -> resolve ( $val );
2012-07-20 13:59:54 +01:00
}
return $value ;
}
2012-11-10 16:18:12 +00:00
if ( ! is_string ( $value )) {
2012-07-10 07:56:32 +01:00
return $value ;
2012-07-10 05:22:39 +01:00
}
2017-10-29 08:23:24 +00:00
$escapedValue = preg_replace_callback ( '/%%|%([^%\s]++)%/' , function ( $match ) use ( $value ) {
2012-07-04 13:24:46 +01:00
// skip %%
if ( ! isset ( $match [ 1 ])) {
return '%%' ;
}
2016-11-29 17:09:44 +00:00
if ( preg_match ( '/^env\(\w+\)$/' , $match [ 1 ])) {
throw new RuntimeException ( sprintf ( 'Using "%%%s%%" is not allowed in routing configuration.' , $match [ 1 ]));
}
2017-10-29 08:23:24 +00:00
$resolved = ( $this -> paramFetcher )( $match [ 1 ]);
2012-07-04 13:24:46 +01:00
if ( is_string ( $resolved ) || is_numeric ( $resolved )) {
2017-02-22 23:13:41 +00:00
$this -> collectedParameters [ $match [ 1 ]] = $resolved ;
2012-07-04 13:24:46 +01:00
return ( string ) $resolved ;
}
throw new RuntimeException ( sprintf (
2014-09-21 19:53:12 +01:00
'The container parameter "%s", used in the route configuration value "%s", ' .
2013-10-24 17:39:19 +01:00
'must be a string or numeric, but it is of type %s.' ,
$match [ 1 ],
$value ,
gettype ( $resolved )
)
2012-07-04 13:24:46 +01:00
);
}, $value );
return str_replace ( '%%' , '%' , $escapedValue );
}
2017-03-10 18:38:01 +00:00
/**
* { @ inheritdoc }
*/
public static function getSubscribedServices ()
{
return array (
'routing.loader' => LoaderInterface :: class ,
);
}
2011-09-14 07:47:38 +01:00
}