make scheme and method requirements first-class citizen in Route

This commit is contained in:
Tobias Schultze 2012-11-13 23:39:53 +01:00
parent 18c520a5e8
commit 10183ded68
2 changed files with 166 additions and 7 deletions

View File

@ -15,6 +15,7 @@ namespace Symfony\Component\Routing;
* A Route describes a route and its parameters.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Tobias Schultze <http://tobion.de>
*
* @api
*/
@ -30,7 +31,17 @@ class Route implements \Serializable
*/
private $hostnamePattern = '';
/**
/**
* @var array
*/
private $schemes = array();
/**
* @var array
*/
private $methods = array();
/**
* @var array
*/
private $defaults = array();
@ -59,21 +70,32 @@ class Route implements \Serializable
*
* * compiler_class: A class name able to compile this route instance (RouteCompiler by default)
*
* @param string $pattern The path pattern to match
* @param array $defaults An array of default parameter values
* @param array $requirements An array of requirements for parameters (regexes)
* @param array $options An array of options
* @param string $hostnamePattern The hostname pattern to match
* @param string $pattern The path pattern to match
* @param array $defaults An array of default parameter values
* @param array $requirements An array of requirements for parameters (regexes)
* @param array $options An array of options
* @param string $hostnamePattern The hostname pattern to match
* @param string|array $schemes A required URI scheme or an array of restricted schemes
* @param string|array $methods A required HTTP method or an array of restricted methods
*
* @api
*/
public function __construct($pattern, array $defaults = array(), array $requirements = array(), array $options = array(), $hostnamePattern = '')
public function __construct($pattern, array $defaults = array(), array $requirements = array(), array $options = array(),
$hostnamePattern = '', $schemes = array(), $methods = array())
{
$this->setPattern($pattern);
$this->setDefaults($defaults);
$this->setRequirements($requirements);
$this->setOptions($options);
$this->setHostnamePattern($hostnamePattern);
// The conditions make sure that an initial empty $schemes/$methods does not override the corresponding requirement.
// They can be removed when the BC layer is removed.
if ($schemes) {
$this->setSchemes($schemes);
}
if ($methods) {
$this->setMethods($methods);
}
}
public function serialize()
@ -84,6 +106,8 @@ class Route implements \Serializable
'defaults' => $this->defaults,
'requirements' => $this->requirements,
'options' => $this->options,
'schemes' => $this->schemes,
'methods' => $this->methods,
));
}
@ -95,6 +119,8 @@ class Route implements \Serializable
$this->defaults = $data['defaults'];
$this->requirements = $data['requirements'];
$this->options = $data['options'];
$this->schemes = $data['schemes'];
$this->methods = $data['methods'];
}
/**
@ -149,6 +175,80 @@ class Route implements \Serializable
return $this;
}
/**
* Returns the lowercased schemes this route is restricted to.
* So an empty array means that any scheme is allowed.
*
* @return array The schemes
*/
public function getSchemes()
{
return $this->schemes;
}
/**
* Sets the schemes (e.g. 'https') this route is restricted to.
* So an empty array means that any scheme is allowed.
*
* This method implements a fluent interface.
*
* @param string|array $schemes The scheme or an array of schemes
*
* @return Route The current Route instance
*/
public function setSchemes($schemes)
{
$this->schemes = array_map('strtolower', (array) $schemes);
// this is to keep BC and will be removed in a future version
if ($this->schemes) {
$this->requirements['_scheme'] = implode('|', $this->schemes);
} else {
unset($this->requirements['_scheme']);
}
$this->compiled = null;
return $this;
}
/**
* Returns the uppercased HTTP methods this route is restricted to.
* So an empty array means that any method is allowed.
*
* @return array The schemes
*/
public function getMethods()
{
return $this->methods;
}
/**
* Sets the HTTP methods (e.g. 'POST') this route is restricted to.
* So an empty array means that any method is allowed.
*
* This method implements a fluent interface.
*
* @param string|array $methods The method or an array of methods
*
* @return Route The current Route instance
*/
public function setMethods($methods)
{
$this->methods = array_map('strtoupper', (array) $methods);
// this is to keep BC and will be removed in a future version
if ($this->methods) {
$this->requirements['_method'] = implode('|', $this->methods);
} else {
unset($this->requirements['_method']);
}
$this->compiled = null;
return $this;
}
/**
* Returns the options.
*
@ -454,6 +554,13 @@ class Route implements \Serializable
throw new \InvalidArgumentException(sprintf('Routing requirement for "%s" cannot be empty.', $key));
}
// this is to keep BC and will be removed in a future version
if ('_scheme' === $key) {
$this->setSchemes(explode('|', $regex));
} elseif ('_method' === $key) {
$this->setMethods(explode('|', $regex));
}
return $regex;
}
}

View File

@ -23,6 +23,14 @@ class RouteTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(array('foo' => '\d+'), $route->getRequirements(), '__construct() takes requirements as its third argument');
$this->assertEquals('bar', $route->getOption('foo'), '__construct() takes options as its fourth argument');
$this->assertEquals('{locale}.example.com', $route->getHostnamePattern(), '__construct() takes a hostname pattern as its fifth argument');
$route = new Route('/', array(), array(), array(), '', array('Https'), array('POST', 'put'));
$this->assertEquals(array('https'), $route->getSchemes(), '__construct() takes schemes as its sixth argument and lowercases it');
$this->assertEquals(array('POST', 'PUT'), $route->getMethods(), '__construct() takes methods as its seventh argument and uppercases it');
$route = new Route('/', array(), array(), array(), '', 'Https', 'Post');
$this->assertEquals(array('https'), $route->getSchemes(), '__construct() takes a single scheme as its sixth argument');
$this->assertEquals(array('POST'), $route->getMethods(), '__construct() takes a single method as its seventh argument');
}
public function testPattern()
@ -129,6 +137,50 @@ class RouteTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('{locale}.example.net', $route->getHostnamePattern(), '->setHostnamePattern() sets the hostname pattern');
}
public function testScheme()
{
$route = new Route('/');
$this->assertEquals(array(), $route->getSchemes(), 'schemes is initialized with array()');
$route->setSchemes('hTTp');
$this->assertEquals(array('http'), $route->getSchemes(), '->setSchemes() accepts a single scheme string and lowercases it');
$route->setSchemes(array('HttpS', 'hTTp'));
$this->assertEquals(array('https', 'http'), $route->getSchemes(), '->setSchemes() accepts an array of schemes and lowercases them');
}
public function testSchemeIsBC()
{
$route = new Route('/');
$route->setRequirement('_scheme', 'http|https');
$this->assertEquals('http|https', $route->getRequirement('_scheme'));
$this->assertEquals(array('http', 'https'), $route->getSchemes());
$route->setSchemes(array('hTTp'));
$this->assertEquals('http', $route->getRequirement('_scheme'));
$route->setSchemes(array());
$this->assertNull($route->getRequirement('_scheme'));
}
public function testMethod()
{
$route = new Route('/');
$this->assertEquals(array(), $route->getMethods(), 'methods is initialized with array()');
$route->setMethods('gEt');
$this->assertEquals(array('GET'), $route->getMethods(), '->setMethods() accepts a single method string and uppercases it');
$route->setMethods(array('gEt', 'PosT'));
$this->assertEquals(array('GET', 'POST'), $route->getMethods(), '->setMethods() accepts an array of methods and uppercases them');
}
public function testMethodIsBC()
{
$route = new Route('/');
$route->setRequirement('_method', 'GET|POST');
$this->assertEquals('GET|POST', $route->getRequirement('_method'));
$this->assertEquals(array('GET', 'POST'), $route->getMethods());
$route->setMethods(array('gEt'));
$this->assertEquals('GET', $route->getRequirement('_method'));
$route->setMethods(array());
$this->assertNull($route->getRequirement('_method'));
}
public function testCompile()
{
$route = new Route('/{foo}');