diff --git a/src/Symfony/Component/Routing/Annotation/Route.php b/src/Symfony/Component/Routing/Annotation/Route.php
index abdbea27c6..f6100731dd 100644
--- a/src/Symfony/Component/Routing/Annotation/Route.php
+++ b/src/Symfony/Component/Routing/Annotation/Route.php
@@ -28,6 +28,7 @@ class Route
private $host;
private $methods;
private $schemes;
+ private $condition;
/**
* Constructor.
@@ -153,4 +154,14 @@ class Route
{
return $this->methods;
}
+
+ public function setCondition($condition)
+ {
+ $this->condition = $condition;
+ }
+
+ public function getCondition()
+ {
+ return $this->condition;
+ }
}
diff --git a/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php b/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php
index 7abab5a631..af70a888b8 100644
--- a/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php
+++ b/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php
@@ -116,6 +116,7 @@ abstract class AnnotationClassLoader implements LoaderInterface
'schemes' => array(),
'methods' => array(),
'host' => '',
+ 'condition' => '',
);
$class = new \ReflectionClass($class);
@@ -154,6 +155,10 @@ abstract class AnnotationClassLoader implements LoaderInterface
if (null !== $annot->getHost()) {
$globals['host'] = $annot->getHost();
}
+
+ if (null !== $annot->getCondition()) {
+ $globals['condition'] = $annot->getCondition();
+ }
}
$collection = new RouteCollection();
@@ -194,7 +199,12 @@ abstract class AnnotationClassLoader implements LoaderInterface
$host = $globals['host'];
}
- $route = new Route($globals['path'].$annot->getPath(), $defaults, $requirements, $options, $host, $schemes, $methods);
+ $condition = $annot->getCondition();
+ if (null === $condition) {
+ $condition = $globals['condition'];
+ }
+
+ $route = new Route($globals['path'].$annot->getPath(), $defaults, $requirements, $options, $host, $schemes, $methods, $condition);
$this->configureRoute($route, $class, $method, $annot);
diff --git a/src/Symfony/Component/Routing/Loader/XmlFileLoader.php b/src/Symfony/Component/Routing/Loader/XmlFileLoader.php
index da7b33d856..e854202f70 100644
--- a/src/Symfony/Component/Routing/Loader/XmlFileLoader.php
+++ b/src/Symfony/Component/Routing/Loader/XmlFileLoader.php
@@ -129,9 +129,9 @@ class XmlFileLoader extends FileLoader
$schemes = preg_split('/[\s,\|]++/', $node->getAttribute('schemes'), -1, PREG_SPLIT_NO_EMPTY);
$methods = preg_split('/[\s,\|]++/', $node->getAttribute('methods'), -1, PREG_SPLIT_NO_EMPTY);
- list($defaults, $requirements, $options) = $this->parseConfigs($node, $path);
+ list($defaults, $requirements, $options, $condition) = $this->parseConfigs($node, $path);
- $route = new Route($node->getAttribute('path'), $defaults, $requirements, $options, $node->getAttribute('host'), $schemes, $methods);
+ $route = new Route($node->getAttribute('path'), $defaults, $requirements, $options, $node->getAttribute('host'), $schemes, $methods, $condition);
$collection->add($id, $route);
}
@@ -157,7 +157,7 @@ class XmlFileLoader extends FileLoader
$schemes = $node->hasAttribute('schemes') ? preg_split('/[\s,\|]++/', $node->getAttribute('schemes'), -1, PREG_SPLIT_NO_EMPTY) : null;
$methods = $node->hasAttribute('methods') ? preg_split('/[\s,\|]++/', $node->getAttribute('methods'), -1, PREG_SPLIT_NO_EMPTY) : null;
- list($defaults, $requirements, $options) = $this->parseConfigs($node, $path);
+ list($defaults, $requirements, $options, $condition) = $this->parseConfigs($node, $path);
$this->setCurrentDir(dirname($path));
@@ -211,6 +211,7 @@ class XmlFileLoader extends FileLoader
$defaults = array();
$requirements = array();
$options = array();
+ $condition = null;
foreach ($node->getElementsByTagNameNS(self::NAMESPACE_URI, '*') as $n) {
switch ($n->localName) {
@@ -228,11 +229,14 @@ class XmlFileLoader extends FileLoader
case 'option':
$options[$n->getAttribute('key')] = trim($n->textContent);
break;
+ case 'condition':
+ $condition = trim($n->textContent);
+ break;
default:
throw new \InvalidArgumentException(sprintf('Unknown tag "%s" used in file "%s". Expected "default", "requirement" or "option".', $n->localName, $path));
}
}
- return array($defaults, $requirements, $options);
+ return array($defaults, $requirements, $options, $condition);
}
}
diff --git a/src/Symfony/Component/Routing/Loader/YamlFileLoader.php b/src/Symfony/Component/Routing/Loader/YamlFileLoader.php
index 9deea7fe4f..d3eaea42e6 100644
--- a/src/Symfony/Component/Routing/Loader/YamlFileLoader.php
+++ b/src/Symfony/Component/Routing/Loader/YamlFileLoader.php
@@ -28,7 +28,7 @@ use Symfony\Component\Config\Loader\FileLoader;
class YamlFileLoader extends FileLoader
{
private static $availableKeys = array(
- 'resource', 'type', 'prefix', 'pattern', 'path', 'host', 'schemes', 'methods', 'defaults', 'requirements', 'options',
+ 'resource', 'type', 'prefix', 'pattern', 'path', 'host', 'schemes', 'methods', 'defaults', 'requirements', 'options', 'condition'
);
private $yamlParser;
@@ -123,8 +123,9 @@ class YamlFileLoader extends FileLoader
$host = isset($config['host']) ? $config['host'] : '';
$schemes = isset($config['schemes']) ? $config['schemes'] : array();
$methods = isset($config['methods']) ? $config['methods'] : array();
+ $condition = isset($config['condition']) ? $config['condition'] : null;
- $route = new Route($config['path'], $defaults, $requirements, $options, $host, $schemes, $methods);
+ $route = new Route($config['path'], $defaults, $requirements, $options, $host, $schemes, $methods, $condition);
$collection->add($name, $route);
}
diff --git a/src/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd b/src/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd
index daea814386..9ab969a41d 100644
--- a/src/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd
+++ b/src/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd
@@ -29,6 +29,7 @@
+
@@ -61,4 +62,9 @@
+
+
+
+
+
diff --git a/src/Symfony/Component/Routing/Matcher/Dumper/ApacheMatcherDumper.php b/src/Symfony/Component/Routing/Matcher/Dumper/ApacheMatcherDumper.php
index 01d8c03589..5b32684876 100644
--- a/src/Symfony/Component/Routing/Matcher/Dumper/ApacheMatcherDumper.php
+++ b/src/Symfony/Component/Routing/Matcher/Dumper/ApacheMatcherDumper.php
@@ -50,6 +50,9 @@ class ApacheMatcherDumper extends MatcherDumper
$prevHostRegex = '';
foreach ($this->getRoutes()->all() as $name => $route) {
+ if ($route->getCondition()) {
+ throw new \LogicException(sprintf('Unable to dump the routes for Apache as route "%s" has a condition.', $name));
+ }
$compiledRoute = $route->compile();
$hostRegex = $compiledRoute->getHostRegex();
diff --git a/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php b/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php
index dc17ffbe98..a412fa7806 100644
--- a/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php
+++ b/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php
@@ -13,6 +13,7 @@ namespace Symfony\Component\Routing\Matcher\Dumper;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
+use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
/**
* PhpMatcherDumper creates a PHP class able to match URLs for a given set of routes.
@@ -23,6 +24,8 @@ use Symfony\Component\Routing\RouteCollection;
*/
class PhpMatcherDumper extends MatcherDumper
{
+ private $expressionLanguage;
+
/**
* Dumps a set of routes to a PHP class.
*
@@ -91,6 +94,8 @@ EOF;
{
\$allow = array();
\$pathinfo = rawurldecode(\$pathinfo);
+ \$context = \$this->context;
+ \$request = \$this->request;
$code
@@ -237,6 +242,10 @@ EOF;
$hostMatches = true;
}
+ if ($route->getCondition()) {
+ $conditions[] = $this->getExpressionLanguage()->compile($route->getCondition(), array('context', 'request'));
+ }
+
$conditions = implode(' && ', $conditions);
$code .= <<context->getMethod() != '$methods[0]') {
@@ -375,4 +383,16 @@ EOF;
return $tree;
}
+
+ private function getExpressionLanguage()
+ {
+ if (null === $this->expressionLanguage) {
+ if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) {
+ throw new RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
+ }
+ $this->expressionLanguage = new ExpressionLanguage();
+ }
+
+ return $this->expressionLanguage;
+ }
}
diff --git a/src/Symfony/Component/Routing/Matcher/RedirectableUrlMatcher.php b/src/Symfony/Component/Routing/Matcher/RedirectableUrlMatcher.php
index 51e80057cd..56fcb604cc 100644
--- a/src/Symfony/Component/Routing/Matcher/RedirectableUrlMatcher.php
+++ b/src/Symfony/Component/Routing/Matcher/RedirectableUrlMatcher.php
@@ -50,6 +50,11 @@ abstract class RedirectableUrlMatcher extends UrlMatcher implements Redirectable
*/
protected function handleRouteRequirements($pathinfo, $name, Route $route)
{
+ // expression condition
+ if ($route->getCondition() && !$this->getExpressionLanguage()->evaluate($route->getCondition(), array('context' => $this->context, 'request' => $this->request))) {
+ return array(self::REQUIREMENT_MISMATCH, null);
+ }
+
// check HTTP scheme requirement
$scheme = $route->getRequirement('_scheme');
if ($scheme && $this->context->getScheme() !== $scheme) {
diff --git a/src/Symfony/Component/Routing/Matcher/TraceableUrlMatcher.php b/src/Symfony/Component/Routing/Matcher/TraceableUrlMatcher.php
index c09f83e86a..e70063b7b9 100644
--- a/src/Symfony/Component/Routing/Matcher/TraceableUrlMatcher.php
+++ b/src/Symfony/Component/Routing/Matcher/TraceableUrlMatcher.php
@@ -94,6 +94,15 @@ class TraceableUrlMatcher extends UrlMatcher
}
}
+ // check condition
+ if ($condition = $route->getCondition()) {
+ if (!$this->getExpressionLanguage()->evaluate($condition, array('context' => $this->context, 'request' => $this->request))) {
+ $this->addTrace(sprintf('Condition "%s" does not evaluate to "true"', $condition), self::ROUTE_ALMOST_MATCHES, $name, $route);
+
+ continue;
+ }
+ }
+
// check HTTP scheme requirement
if ($scheme = $route->getRequirement('_scheme')) {
if ($this->context->getScheme() !== $scheme) {
diff --git a/src/Symfony/Component/Routing/Matcher/UrlMatcher.php b/src/Symfony/Component/Routing/Matcher/UrlMatcher.php
index db18ec4e7b..b4b7055db1 100644
--- a/src/Symfony/Component/Routing/Matcher/UrlMatcher.php
+++ b/src/Symfony/Component/Routing/Matcher/UrlMatcher.php
@@ -16,6 +16,8 @@ use Symfony\Component\Routing\Exception\ResourceNotFoundException;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\Route;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
/**
* UrlMatcher matches URL based on a set of routes.
@@ -24,7 +26,7 @@ use Symfony\Component\Routing\Route;
*
* @api
*/
-class UrlMatcher implements UrlMatcherInterface
+class UrlMatcher implements UrlMatcherInterface, RequestMatcherInterface
{
const REQUIREMENT_MATCH = 0;
const REQUIREMENT_MISMATCH = 1;
@@ -45,6 +47,9 @@ class UrlMatcher implements UrlMatcherInterface
*/
protected $routes;
+ protected $request;
+ protected $expressionLanguage;
+
/**
* Constructor.
*
@@ -91,6 +96,20 @@ class UrlMatcher implements UrlMatcherInterface
: new ResourceNotFoundException();
}
+ /**
+ * {@inheritdoc}
+ */
+ public function matchRequest(Request $request)
+ {
+ $this->request = $request;
+
+ $ret = $this->match($request->getPathInfo());
+
+ $this->request = null;
+
+ return $ret;
+ }
+
/**
* Tries to match a URL with a set of routes.
*
@@ -180,11 +199,18 @@ class UrlMatcher implements UrlMatcherInterface
*/
protected function handleRouteRequirements($pathinfo, $name, Route $route)
{
+ // expression condition
+ if ($route->getCondition() && !$this->getExpressionLanguage()->evaluate($route->getCondition(), array('context' => $this->context, 'request' => $this->request))) {
+ return array(self::REQUIREMENT_MISMATCH, null);
+ }
+
// check HTTP scheme requirement
$scheme = $route->getRequirement('_scheme');
- $status = $scheme && $scheme !== $this->context->getScheme() ? self::REQUIREMENT_MISMATCH : self::REQUIREMENT_MATCH;
+ if ($scheme && $scheme !== $this->context->getScheme()) {
+ return array(self::REQUIREMENT_MISMATCH, null);
+ }
- return array($status, null);
+ return array(self::REQUIREMENT_MATCH, null);
}
/**
@@ -205,4 +231,16 @@ class UrlMatcher implements UrlMatcherInterface
return $defaults;
}
+
+ protected function getExpressionLanguage()
+ {
+ if (null === $this->expressionLanguage) {
+ if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) {
+ throw new RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
+ }
+ $this->expressionLanguage = new ExpressionLanguage();
+ }
+
+ return $this->expressionLanguage;
+ }
}
diff --git a/src/Symfony/Component/Routing/Route.php b/src/Symfony/Component/Routing/Route.php
index 5bc535c683..aac654b01e 100644
--- a/src/Symfony/Component/Routing/Route.php
+++ b/src/Symfony/Component/Routing/Route.php
@@ -61,6 +61,8 @@ class Route implements \Serializable
*/
private $compiled;
+ private $condition;
+
/**
* Constructor.
*
@@ -75,10 +77,11 @@ class Route implements \Serializable
* @param string $host The host 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
+ * @param string $condition A condition that should evaluate to true for the route to match
*
* @api
*/
- public function __construct($path, array $defaults = array(), array $requirements = array(), array $options = array(), $host = '', $schemes = array(), $methods = array())
+ public function __construct($path, array $defaults = array(), array $requirements = array(), array $options = array(), $host = '', $schemes = array(), $methods = array(), $condition = null)
{
$this->setPath($path);
$this->setDefaults($defaults);
@@ -93,6 +96,7 @@ class Route implements \Serializable
if ($methods) {
$this->setMethods($methods);
}
+ $this->setCondition($condition);
}
public function serialize()
@@ -105,6 +109,7 @@ class Route implements \Serializable
'options' => $this->options,
'schemes' => $this->schemes,
'methods' => $this->methods,
+ 'condition' => $this->condition,
));
}
@@ -118,6 +123,7 @@ class Route implements \Serializable
$this->options = $data['options'];
$this->schemes = $data['schemes'];
$this->methods = $data['methods'];
+ $this->condition = $data['condition'];
}
/**
@@ -543,6 +549,33 @@ class Route implements \Serializable
return $this;
}
+ /**
+ * Returns the condition.
+ *
+ * @return string The condition
+ */
+ public function getCondition()
+ {
+ return $this->condition;
+ }
+
+ /**
+ * Sets the condition.
+ *
+ * This method implements a fluent interface.
+ *
+ * @param string $condition The condition
+ *
+ * @return Route The current Route instance
+ */
+ public function setCondition($condition)
+ {
+ $this->condition = (string) $condition;
+ $this->compiled = null;
+
+ return $this;
+ }
+
/**
* Compiles the route.
*
diff --git a/src/Symfony/Component/Routing/RouteCollection.php b/src/Symfony/Component/Routing/RouteCollection.php
index 499fe0f04f..f028324242 100644
--- a/src/Symfony/Component/Routing/RouteCollection.php
+++ b/src/Symfony/Component/Routing/RouteCollection.php
@@ -177,6 +177,20 @@ class RouteCollection implements \IteratorAggregate, \Countable
}
}
+ /**
+ * Sets a condition on all routes.
+ *
+ * Existing conditions will be overridden.
+ *
+ * @param string $condition The condition
+ */
+ public function setCondition($condition)
+ {
+ foreach ($this->routes as $route) {
+ $route->setCondition($condition);
+ }
+ }
+
/**
* Adds defaults to all routes.
*
diff --git a/src/Symfony/Component/Routing/Tests/Annotation/RouteTest.php b/src/Symfony/Component/Routing/Tests/Annotation/RouteTest.php
index b58869f7af..bd0167089e 100644
--- a/src/Symfony/Component/Routing/Tests/Annotation/RouteTest.php
+++ b/src/Symfony/Component/Routing/Tests/Annotation/RouteTest.php
@@ -35,15 +35,16 @@ class RouteTest extends \PHPUnit_Framework_TestCase
public function getValidParameters()
{
return array(
- array('value', '/Blog', 'getPattern'),
- array('value', '/Blog', 'getPath'),
- array('requirements', array('_method' => 'GET'), 'getRequirements'),
- array('options', array('compiler_class' => 'RouteCompiler'), 'getOptions'),
- array('name', 'blog_index', 'getName'),
- array('defaults', array('_controller' => 'MyBlogBundle:Blog:index'), 'getDefaults'),
- array('schemes', array('https'), 'getSchemes'),
- array('methods', array('GET', 'POST'), 'getMethods'),
- array('host', array('{locale}.example.com'), 'getHost')
+ array('value', '/Blog', 'getPattern'),
+ array('value', '/Blog', 'getPath'),
+ array('requirements', array('_method' => 'GET'), 'getRequirements'),
+ array('options', array('compiler_class' => 'RouteCompiler'), 'getOptions'),
+ array('name', 'blog_index', 'getName'),
+ array('defaults', array('_controller' => 'MyBlogBundle:Blog:index'), 'getDefaults'),
+ array('schemes', array('https'), 'getSchemes'),
+ array('methods', array('GET', 'POST'), 'getMethods'),
+ array('host', array('{locale}.example.com'), 'getHost'),
+ array('condition', array('context.getMethod() == "GET"'), 'getCondition'),
);
}
}
diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.php b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.php
index e5f7665c81..248a4f153f 100644
--- a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.php
+++ b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.php
@@ -24,6 +24,8 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Matcher\UrlMatcher
{
$allow = array();
$pathinfo = rawurldecode($pathinfo);
+ $context = $this->context;
+ $request = $this->request;
// foo
if (0 === strpos($pathinfo, '/foo') && preg_match('#^/foo/(?Pbaz|symfony)$#s', $pathinfo, $matches)) {
diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.php b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.php
index ad157909b8..d7b99d67b9 100644
--- a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.php
+++ b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.php
@@ -24,6 +24,8 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Tests\Fixtures\Redirec
{
$allow = array();
$pathinfo = rawurldecode($pathinfo);
+ $context = $this->context;
+ $request = $this->request;
// foo
if (0 === strpos($pathinfo, '/foo') && preg_match('#^/foo/(?Pbaz|symfony)$#s', $pathinfo, $matches)) {
diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher3.php b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher3.php
index f2f642eb86..c3463fa772 100644
--- a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher3.php
+++ b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher3.php
@@ -24,6 +24,8 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Matcher\UrlMatcher
{
$allow = array();
$pathinfo = rawurldecode($pathinfo);
+ $context = $this->context;
+ $request = $this->request;
if (0 === strpos($pathinfo, '/rootprefix')) {
// static
@@ -38,6 +40,11 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Matcher\UrlMatcher
}
+ // with-condition
+ if ($pathinfo === '/with-condition' && ($context->getMethod() == "GET")) {
+ return array('_route' => 'with-condition');
+ }
+
throw 0 < count($allow) ? new MethodNotAllowedException(array_unique($allow)) : new ResourceNotFoundException();
}
}
diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/validpattern.php b/src/Symfony/Component/Routing/Tests/Fixtures/validpattern.php
index b8bbbb5f8f..b652d94656 100644
--- a/src/Symfony/Component/Routing/Tests/Fixtures/validpattern.php
+++ b/src/Symfony/Component/Routing/Tests/Fixtures/validpattern.php
@@ -10,14 +10,18 @@ $collection->add('blog_show', new Route(
array('compiler_class' => 'RouteCompiler'),
'{locale}.example.com',
array('https'),
- array('GET','POST','put','OpTiOnS')
+ array('GET','POST','put','OpTiOnS'),
+ 'context.getMethod() == "GET"'
));
$collection->add('blog_show_legacy', new Route(
'/blog/{slug}',
array('_controller' => 'MyBlogBundle:Blog:show'),
array('_method' => 'GET|POST|put|OpTiOnS', '_scheme' => 'https', 'locale' => '\w+',),
array('compiler_class' => 'RouteCompiler'),
- '{locale}.example.com'
+ '{locale}.example.com',
+ array(),
+ array(),
+ 'context.getMethod() == "GET"'
));
return $collection;
diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/validpattern.xml b/src/Symfony/Component/Routing/Tests/Fixtures/validpattern.xml
index b9f22347b4..cfee9d6882 100644
--- a/src/Symfony/Component/Routing/Tests/Fixtures/validpattern.xml
+++ b/src/Symfony/Component/Routing/Tests/Fixtures/validpattern.xml
@@ -8,6 +8,7 @@
MyBundle:Blog:show
\w+
+ context.getMethod() == "GET"
@@ -17,5 +18,6 @@
hTTps
\w+
+ context.getMethod() == "GET"
diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/validpattern.yml b/src/Symfony/Component/Routing/Tests/Fixtures/validpattern.yml
index 4ada883219..48cf7f8817 100644
--- a/src/Symfony/Component/Routing/Tests/Fixtures/validpattern.yml
+++ b/src/Symfony/Component/Routing/Tests/Fixtures/validpattern.yml
@@ -5,6 +5,7 @@ blog_show:
requirements: { 'locale': '\w+' }
methods: ['GET','POST','put','OpTiOnS']
schemes: ['https']
+ condition: 'context.getMethod() == "GET"'
options:
compiler_class: RouteCompiler
@@ -13,5 +14,6 @@ blog_show_legacy:
defaults: { _controller: "MyBundle:Blog:show" }
host: "{locale}.example.com"
requirements: { '_method': 'GET|POST|put|OpTiOnS', _scheme: https, 'locale': '\w+' }
+ condition: 'context.getMethod() == "GET"'
options:
compiler_class: RouteCompiler
diff --git a/src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderTest.php b/src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderTest.php
index 5b7325c317..c60997902e 100644
--- a/src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderTest.php
+++ b/src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderTest.php
@@ -84,7 +84,12 @@ class AnnotationClassLoaderTest extends AbstractAnnotationLoaderTest
array(
'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BarClass',
array('name' => 'route1', 'defaults' => array('arg2' => 'foobar')),
- array('arg2' => false, 'arg3' => 'defaultValue3')
+ array('arg2' => 'defaultValue2', 'arg3' =>'defaultValue3')
+ ),
+ array(
+ 'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BarClass',
+ array('name' => 'route1', 'defaults' => array('arg2' => 'foo'), 'condition' => 'context.getMethod() == "GET"'),
+ array('arg2' => 'defaultValue2', 'arg3' =>'defaultValue3')
),
);
}
@@ -102,6 +107,7 @@ class AnnotationClassLoaderTest extends AbstractAnnotationLoaderTest
'defaults' => array(),
'schemes' => array(),
'methods' => array(),
+ 'condition' => null,
), $routeDatas);
$this->reader
@@ -116,6 +122,7 @@ class AnnotationClassLoaderTest extends AbstractAnnotationLoaderTest
$this->assertSame($routeDatas['requirements'],$route->getRequirements(), '->load preserves requirements annotation');
$this->assertCount(0, array_intersect($route->getOptions(), $routeDatas['options']), '->load preserves options annotation');
$this->assertSame(array_replace($methodArgs, $routeDatas['defaults']), $route->getDefaults(), '->load preserves defaults annotation');
+ $this->assertEquals($routeDatas['condition'], $route->getCondition(), '->load preserves condition annotation');
}
private function getAnnotatedRoute($datas)
diff --git a/src/Symfony/Component/Routing/Tests/Loader/XmlFileLoaderTest.php b/src/Symfony/Component/Routing/Tests/Loader/XmlFileLoaderTest.php
index b678b3a8c8..c38adbd938 100644
--- a/src/Symfony/Component/Routing/Tests/Loader/XmlFileLoaderTest.php
+++ b/src/Symfony/Component/Routing/Tests/Loader/XmlFileLoaderTest.php
@@ -45,6 +45,7 @@ class XmlFileLoaderTest extends \PHPUnit_Framework_TestCase
$this->assertSame('RouteCompiler', $route->getOption('compiler_class'));
$this->assertEquals(array('GET', 'POST', 'PUT', 'OPTIONS'), $route->getMethods());
$this->assertEquals(array('https'), $route->getSchemes());
+ $this->assertEquals('context.getMethod() == "GET"', $route->getCondition());
}
}
diff --git a/src/Symfony/Component/Routing/Tests/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/Routing/Tests/Loader/YamlFileLoaderTest.php
index 1463326094..f030106205 100644
--- a/src/Symfony/Component/Routing/Tests/Loader/YamlFileLoaderTest.php
+++ b/src/Symfony/Component/Routing/Tests/Loader/YamlFileLoaderTest.php
@@ -79,6 +79,7 @@ class YamlFileLoaderTest extends \PHPUnit_Framework_TestCase
$this->assertSame('RouteCompiler', $route->getOption('compiler_class'));
$this->assertEquals(array('GET', 'POST', 'PUT', 'OPTIONS'), $route->getMethods());
$this->assertEquals(array('https'), $route->getSchemes());
+ $this->assertEquals('context.getMethod() == "GET"', $route->getCondition());
}
}
diff --git a/src/Symfony/Component/Routing/Tests/Matcher/Dumper/PhpMatcherDumperTest.php b/src/Symfony/Component/Routing/Tests/Matcher/Dumper/PhpMatcherDumperTest.php
index 542ede85c0..473af6aa5c 100644
--- a/src/Symfony/Component/Routing/Tests/Matcher/Dumper/PhpMatcherDumperTest.php
+++ b/src/Symfony/Component/Routing/Tests/Matcher/Dumper/PhpMatcherDumperTest.php
@@ -251,6 +251,9 @@ class PhpMatcherDumperTest extends \PHPUnit_Framework_TestCase
$rootprefixCollection->add('static', new Route('/test'));
$rootprefixCollection->add('dynamic', new Route('/{var}'));
$rootprefixCollection->addPrefix('rootprefix');
+ $route = new Route('/with-condition');
+ $route->setCondition('context.getMethod() == "GET"');
+ $rootprefixCollection->add('with-condition', $route);
return array(
array($collection, 'url_matcher1.php', array()),
diff --git a/src/Symfony/Component/Routing/Tests/Matcher/TraceableUrlMatcherTest.php b/src/Symfony/Component/Routing/Tests/Matcher/TraceableUrlMatcherTest.php
index 86d8d954c0..de6395226f 100644
--- a/src/Symfony/Component/Routing/Tests/Matcher/TraceableUrlMatcherTest.php
+++ b/src/Symfony/Component/Routing/Tests/Matcher/TraceableUrlMatcherTest.php
@@ -26,13 +26,14 @@ class TraceableUrlMatcherTest extends \PHPUnit_Framework_TestCase
$coll->add('bar1', new Route('/bar/{name}', array(), array('id' => '\w+', '_method' => 'POST')));
$coll->add('bar2', new Route('/foo', array(), array(), array(), 'baz'));
$coll->add('bar3', new Route('/foo1', array(), array(), array(), 'baz'));
+ $coll->add('bar4', new Route('/foo2', array(), array(), array(), 'baz', array(), array(), 'context.getMethod() == "GET"'));
$context = new RequestContext();
$context->setHost('baz');
$matcher = new TraceableUrlMatcher($coll, $context);
$traces = $matcher->getTraces('/babar');
- $this->assertEquals(array(0, 0, 0, 0, 0), $this->getLevels($traces));
+ $this->assertEquals(array(0, 0, 0, 0, 0, 0), $this->getLevels($traces));
$traces = $matcher->getTraces('/foo');
$this->assertEquals(array(1, 0, 0, 2), $this->getLevels($traces));
@@ -41,7 +42,7 @@ class TraceableUrlMatcherTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(array(0, 2), $this->getLevels($traces));
$traces = $matcher->getTraces('/bar/dd');
- $this->assertEquals(array(0, 1, 1, 0, 0), $this->getLevels($traces));
+ $this->assertEquals(array(0, 1, 1, 0, 0, 0), $this->getLevels($traces));
$traces = $matcher->getTraces('/foo1');
$this->assertEquals(array(0, 0, 0, 0, 2), $this->getLevels($traces));
@@ -52,6 +53,9 @@ class TraceableUrlMatcherTest extends \PHPUnit_Framework_TestCase
$traces = $matcher->getTraces('/bar/dd');
$this->assertEquals(array(0, 1, 2), $this->getLevels($traces));
+
+ $traces = $matcher->getTraces('/foo2');
+ $this->assertEquals(array(0, 0, 0, 0, 0, 1), $this->getLevels($traces));
}
public function getLevels($traces)
diff --git a/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php b/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php
index 8a1428f170..b31cada8c0 100644
--- a/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php
+++ b/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php
@@ -321,6 +321,19 @@ class UrlMatcherTest extends \PHPUnit_Framework_TestCase
$matcher->match('/foo');
}
+ /**
+ * @expectedException \Symfony\Component\Routing\Exception\ResourceNotFoundException
+ */
+ public function testCondition()
+ {
+ $coll = new RouteCollection();
+ $route = new Route('/foo');
+ $route->setCondition('context.getMethod() == "POST"');
+ $coll->add('foo', $route);
+ $matcher = new UrlMatcher($coll, new RequestContext());
+ $matcher->match('/foo');
+ }
+
public function testDecodeOnce()
{
$coll = new RouteCollection();
diff --git a/src/Symfony/Component/Routing/Tests/RouteCollectionTest.php b/src/Symfony/Component/Routing/Tests/RouteCollectionTest.php
index 94f2984368..027917bc1a 100644
--- a/src/Symfony/Component/Routing/Tests/RouteCollectionTest.php
+++ b/src/Symfony/Component/Routing/Tests/RouteCollectionTest.php
@@ -244,4 +244,18 @@ class RouteCollectionTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('{locale}.example.com', $routea->getHost());
$this->assertEquals('{locale}.example.com', $routeb->getHost());
}
+
+ public function testSetCondition()
+ {
+ $collection = new RouteCollection();
+ $routea = new Route('/a');
+ $routeb = new Route('/b', array(), array(), array(), '{locale}.example.net', array(), array(), 'context.getMethod() == "GET"');
+ $collection->add('a', $routea);
+ $collection->add('b', $routeb);
+
+ $collection->setCondition('context.getMethod() == "POST"');
+
+ $this->assertEquals('context.getMethod() == "POST"', $routea->getCondition());
+ $this->assertEquals('context.getMethod() == "POST"', $routeb->getCondition());
+ }
}
diff --git a/src/Symfony/Component/Routing/Tests/RouteTest.php b/src/Symfony/Component/Routing/Tests/RouteTest.php
index 47b87f33ab..d63bcbacf6 100644
--- a/src/Symfony/Component/Routing/Tests/RouteTest.php
+++ b/src/Symfony/Component/Routing/Tests/RouteTest.php
@@ -24,9 +24,10 @@ class RouteTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('bar', $route->getOption('foo'), '__construct() takes options as its fourth argument');
$this->assertEquals('{locale}.example.com', $route->getHost(), '__construct() takes a host pattern as its fifth argument');
- $route = new Route('/', array(), array(), array(), '', array('Https'), array('POST', 'put'));
+ $route = new Route('/', array(), array(), array(), '', array('Https'), array('POST', 'put'), 'context.getMethod() == "GET"');
$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');
+ $this->assertEquals('context.getMethod() == "GET"', $route->getCondition(), '__construct() takes a condition as its eight argument');
$route = new Route('/', array(), array(), array(), '', 'Https', 'Post');
$this->assertEquals(array('https'), $route->getSchemes(), '__construct() takes a single scheme as its sixth argument');
@@ -181,6 +182,14 @@ class RouteTest extends \PHPUnit_Framework_TestCase
$this->assertNull($route->getRequirement('_method'));
}
+ public function testCondition()
+ {
+ $route = new Route('/');
+ $this->assertEquals(null, $route->getCondition());
+ $route->setCondition('context.getMethod() == "GET"');
+ $this->assertEquals('context.getMethod() == "GET"', $route->getCondition());
+ }
+
public function testCompile()
{
$route = new Route('/{foo}');
diff --git a/src/Symfony/Component/Routing/composer.json b/src/Symfony/Component/Routing/composer.json
index 0c476b3a68..67b9327834 100644
--- a/src/Symfony/Component/Routing/composer.json
+++ b/src/Symfony/Component/Routing/composer.json
@@ -21,6 +21,7 @@
"require-dev": {
"symfony/config": "~2.2",
"symfony/yaml": "~2.0",
+ "symfony/expression-language": "~2.4",
"doctrine/common": "~2.2",
"psr/log": "~1.0"
},