Skip to content

Commit

Permalink
[Routing] Add strict_parameters option to disable exceptions when a r…
Browse files Browse the repository at this point in the history
…oute generation fails due to an invalid parameter
  • Loading branch information
Seldaek committed Jun 9, 2012
1 parent 3bb7dc0 commit bbef65e
Show file tree
Hide file tree
Showing 8 changed files with 95 additions and 22 deletions.
Expand Up @@ -155,6 +155,7 @@ private function addRouterSection(ArrayNodeDefinition $rootNode)
->scalarNode('type')->end()
->scalarNode('http_port')->defaultValue(80)->end()
->scalarNode('https_port')->defaultValue(443)->end()
->scalarNode('strict_parameters')->defaultTrue()->end()
->end()
->end()
->end()
Expand Down
Expand Up @@ -255,11 +255,12 @@ private function registerRouterConfiguration(array $config, ContainerBuilder $co
$container->setParameter('router.resource', $config['resource']);
$router = $container->findDefinition('router.default');

$argument = $router->getArgument(2);
$argument['strict_parameters'] = $config['strict_parameters'];
if (isset($config['type'])) {
$argument = $router->getArgument(2);
$argument['resource_type'] = $config['type'];
$router->replaceArgument(2, $argument);
}
$router->replaceArgument(2, $argument);

$container->setParameter('request_listener.http_port', $config['http_port']);
$container->setParameter('request_listener.https_port', $config['https_port']);
Expand Down
Expand Up @@ -50,6 +50,7 @@
</service>

<service id="router.default" class="%router.class%" public="false">
<tag name="monolog.logger" channel="router" />
<argument type="service" id="service_container" />
<argument>%router.resource%</argument>
<argument type="collection">
Expand All @@ -65,6 +66,7 @@
<argument key="matcher_cache_class">%router.options.matcher.cache_class%</argument>
</argument>
<argument type="service" id="router.request_context" on-invalid="ignore" />
<argument type="service" id="logger" on-invalid="ignore" />
</service>

<service id="router" alias="router.default" />
Expand Down
Expand Up @@ -49,6 +49,7 @@ public function dump(array $options = array())
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\Exception\RouteNotFoundException;
use Symfony\Component\HttpKernel\Log\LoggerInterface;
/**
* {$options['class']}
Expand All @@ -63,9 +64,10 @@ class {$options['class']} extends {$options['base_class']}
/**
* Constructor.
*/
public function __construct(RequestContext \$context)
public function __construct(RequestContext \$context, LoggerInterface \$logger = null)
{
\$this->context = \$context;
\$this->logger = \$logger;
}
{$this->generateGenerateMethod()}
Expand Down
40 changes: 38 additions & 2 deletions src/Symfony/Component/Routing/Generator/UrlGenerator.php
Expand Up @@ -17,6 +17,7 @@
use Symfony\Component\Routing\Exception\InvalidParameterException;
use Symfony\Component\Routing\Exception\RouteNotFoundException;
use Symfony\Component\Routing\Exception\MissingMandatoryParametersException;
use Symfony\Component\HttpKernel\Log\LoggerInterface;

/**
* UrlGenerator generates a URL based on a set of routes.
Expand All @@ -28,6 +29,8 @@
class UrlGenerator implements UrlGeneratorInterface
{
protected $context;
protected $strictParameters = true;
protected $logger;
protected $decodedChars = array(
// %2F is not valid in a URL, so we don't encode it (which is fine as the requirements explicitly allowed it)
'%2F' => '/',
Expand All @@ -40,13 +43,15 @@ class UrlGenerator implements UrlGeneratorInterface
*
* @param RouteCollection $routes A RouteCollection instance
* @param RequestContext $context The context
* @param LoggerInterface $logger A logger instance
*
* @api
*/
public function __construct(RouteCollection $routes, RequestContext $context)
public function __construct(RouteCollection $routes, RequestContext $context, LoggerInterface $logger = null)
{
$this->routes = $routes;
$this->context = $context;
$this->logger = $logger;
}

/**
Expand All @@ -71,6 +76,28 @@ public function getContext()
return $this->context;
}

/**
* Enables or disables the exception on incorrect parameters.
*
* @param Boolean $enabled
*
* @api
*/
public function setStrictParameters($enabled)
{
$this->strictParameters = $enabled;
}

/**
* Gets the strict check of incorrect parameters.
*
* @return Boolean
*/
public function getStrictParameters()
{
return $this->strictParameters;
}

/**
* {@inheritDoc}
*
Expand Down Expand Up @@ -113,7 +140,16 @@ protected function doGenerate($variables, $defaults, $requirements, $tokens, $pa
if (!$isEmpty = in_array($tparams[$token[3]], array(null, '', false), true)) {
// check requirement
if ($tparams[$token[3]] && !preg_match('#^'.$token[2].'$#', $tparams[$token[3]])) {
throw new InvalidParameterException(sprintf('Parameter "%s" for route "%s" must match "%s" ("%s" given).', $token[3], $name, $token[2], $tparams[$token[3]]));
$message = sprintf('Parameter "%s" for route "%s" must match "%s" ("%s" given).', $token[3], $name, $token[2], $tparams[$token[3]]);
if ($this->strictParameters) {
throw new InvalidParameterException($message);
}

if ($this->logger) {
$this->logger->err($message);
}

return null;
}
}

Expand Down
41 changes: 26 additions & 15 deletions src/Symfony/Component/Routing/Router.php
Expand Up @@ -13,6 +13,7 @@

use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\Config\ConfigCache;
use Symfony\Component\HttpKernel\Log\LoggerInterface;

/**
* The Router class is an example of the integration of all pieces of the
Expand All @@ -29,6 +30,7 @@ class Router implements RouterInterface
protected $collection;
protected $resource;
protected $options;
protected $logger;

/**
* Constructor.
Expand All @@ -37,11 +39,13 @@ class Router implements RouterInterface
* @param mixed $resource The main resource to load
* @param array $options An array of options
* @param RequestContext $context The context
* @param LoggerInterface $logger A logger instance
*/
public function __construct(LoaderInterface $loader, $resource, array $options = array(), RequestContext $context = null)
public function __construct(LoaderInterface $loader, $resource, array $options = array(), RequestContext $context = null, LoggerInterface $logger = null)
{
$this->loader = $loader;
$this->resource = $resource;
$this->logger = $logger;
$this->context = null === $context ? new RequestContext() : $context;
$this->setOptions($options);
}
Expand Down Expand Up @@ -73,6 +77,7 @@ public function setOptions(array $options)
'matcher_dumper_class' => 'Symfony\\Component\\Routing\\Matcher\\Dumper\\PhpMatcherDumper',
'matcher_cache_class' => 'ProjectUrlMatcher',
'resource_type' => null,
'strict_parameters' => true,
);

// check option names and live merge, if errors are encountered Exception will be thrown
Expand Down Expand Up @@ -225,24 +230,30 @@ public function getGenerator()
}

if (null === $this->options['cache_dir'] || null === $this->options['generator_cache_class']) {
return $this->generator = new $this->options['generator_class']($this->getRouteCollection(), $this->context);
}
$this->generator = new $this->options['generator_class']($this->getRouteCollection(), $this->context, $this->logger);
} else {
$class = $this->options['generator_cache_class'];
$cache = new ConfigCache($this->options['cache_dir'].'/'.$class.'.php', $this->options['debug']);
if (!$cache->isFresh($class)) {
$dumper = new $this->options['generator_dumper_class']($this->getRouteCollection());

$options = array(
'class' => $class,
'base_class' => $this->options['generator_base_class'],
);

$cache->write($dumper->dump($options), $this->getRouteCollection()->getResources());
}

$class = $this->options['generator_cache_class'];
$cache = new ConfigCache($this->options['cache_dir'].'/'.$class.'.php', $this->options['debug']);
if (!$cache->isFresh($class)) {
$dumper = new $this->options['generator_dumper_class']($this->getRouteCollection());
require_once $cache;

$options = array(
'class' => $class,
'base_class' => $this->options['generator_base_class'],
);

$cache->write($dumper->dump($options), $this->getRouteCollection()->getResources());
$this->generator = new $class($this->context, $this->logger);
}

require_once $cache;
if (false === $this->options['strict_parameters']) {
$this->generator->setStrictParameters(false);
}

return $this->generator = new $class($this->context);
return $this->generator;
}
}
23 changes: 21 additions & 2 deletions src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php
Expand Up @@ -165,6 +165,25 @@ public function testGenerateForRouteWithInvalidOptionalParameter()
$this->getGenerator($routes)->generate('test', array('foo' => 'bar'), true);
}

public function testGenerateForRouteWithInvalidOptionalParameterNonStrict()
{
$routes = $this->getRoutes('test', new Route('/testing/{foo}', array('foo' => '1'), array('foo' => 'd+')));
$generator = $this->getGenerator($routes);
$generator->setStrictParameters(false);
$this->assertNull($generator->generate('test', array('foo' => 'bar'), true));
}

public function testGenerateForRouteWithInvalidOptionalParameterNonStrictWithLogger()
{
$routes = $this->getRoutes('test', new Route('/testing/{foo}', array('foo' => '1'), array('foo' => 'd+')));
$logger = $this->getMock('Symfony\Component\HttpKernel\Log\LoggerInterface');
$logger->expects($this->once())
->method('err');
$generator = $this->getGenerator($routes, array(), $logger);
$generator->setStrictParameters(false);
$this->assertNull($generator->generate('test', array('foo' => 'bar'), true));
}

/**
* @expectedException Symfony\Component\Routing\Exception\InvalidParameterException
*/
Expand Down Expand Up @@ -206,14 +225,14 @@ public function testWithAnIntegerAsADefaultValue()
$this->assertEquals('/app.php/foo', $this->getGenerator($routes)->generate('test', array('default' => 'foo')));
}

protected function getGenerator(RouteCollection $routes, array $parameters = array())
protected function getGenerator(RouteCollection $routes, array $parameters = array(), $logger = null)
{
$context = new RequestContext('/app.php');
foreach ($parameters as $key => $value) {
$method = 'set'.$key;
$context->$method($value);
}
$generator = new UrlGenerator($routes, $context);
$generator = new UrlGenerator($routes, $context, $logger);

return $generator;
}
Expand Down
1 change: 1 addition & 0 deletions src/Symfony/Component/Routing/composer.json
Expand Up @@ -21,6 +21,7 @@
"require-dev": {
"symfony/config": "2.1.*",
"symfony/yaml": "2.1.*",
"symfony/http-kernel": "2.1.*",
"doctrine/common": ">=2.2,<2.4-dev"
},
"suggest": {
Expand Down

0 comments on commit bbef65e

Please sign in to comment.