bug #22636 [Routing] Expose request in route conditions, if needed and possible (ro0NL)

This PR was squashed before being merged into the 2.7 branch (closes #22636).

Discussion
----------

[Routing] Expose request in route conditions, if needed and possible

| Q             | A
| ------------- | ---
| Branch?       | 2.7
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #16968, #22635
| License       | MIT
| Doc PR        | -

given

```
/**
 * @Route("/", name="homepage", condition="request.isXmlHttpRequest()")
 */
```

```
$ app/console route:match /
```

before

![image](https://cloud.githubusercontent.com/assets/1047696/25716808/b9ab518e-3100-11e7-8b59-21351b5c14ca.png)

after

![image](https://cloud.githubusercontent.com/assets/1047696/25716833/d08065fc-3100-11e7-9462-987b2c6eaa26.png)

Commits
-------

016e976691 [Routing] Expose request in route conditions, if needed and possible
This commit is contained in:
Fabien Potencier 2017-06-14 13:57:27 -07:00
commit f392282984
4 changed files with 28 additions and 3 deletions

View File

@ -49,7 +49,7 @@ 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))) {
if ($route->getCondition() && !$this->getExpressionLanguage()->evaluate($route->getCondition(), array('context' => $this->context, 'request' => $this->request ?: $this->createRequest($pathinfo)))) {
return array(self::REQUIREMENT_MISMATCH, null);
}

View File

@ -105,7 +105,7 @@ class TraceableUrlMatcher extends UrlMatcher
// check condition
if ($condition = $route->getCondition()) {
if (!$this->getExpressionLanguage()->evaluate($condition, array('context' => $this->context, 'request' => $this->request))) {
if (!$this->getExpressionLanguage()->evaluate($condition, array('context' => $this->context, 'request' => $this->request ?: $this->createRequest($pathinfo)))) {
$this->addTrace(sprintf('Condition "%s" does not evaluate to "true"', $condition), self::ROUTE_ALMOST_MATCHES, $name, $route);
continue;

View File

@ -207,7 +207,7 @@ class UrlMatcher implements UrlMatcherInterface, RequestMatcherInterface
protected function handleRouteRequirements($pathinfo, $name, Route $route)
{
// expression condition
if ($route->getCondition() && !$this->getExpressionLanguage()->evaluate($route->getCondition(), array('context' => $this->context, 'request' => $this->request))) {
if ($route->getCondition() && !$this->getExpressionLanguage()->evaluate($route->getCondition(), array('context' => $this->context, 'request' => $this->request ?: $this->createRequest($pathinfo)))) {
return array(self::REQUIREMENT_MISMATCH, null);
}
@ -248,4 +248,19 @@ class UrlMatcher implements UrlMatcherInterface, RequestMatcherInterface
return $this->expressionLanguage;
}
/**
* @internal
*/
protected function createRequest($pathinfo)
{
if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
return null;
}
return Request::create($this->context->getScheme().'://'.$this->context->getHost().$this->context->getBaseUrl().$pathinfo, $this->context->getMethod(), $this->context->getParameters(), array(), array(), array(
'SCRIPT_FILENAME' => $this->context->getBaseUrl(),
'SCRIPT_NAME' => $this->context->getBaseUrl(),
));
}
}

View File

@ -337,6 +337,16 @@ class UrlMatcherTest extends TestCase
$matcher->match('/foo');
}
public function testRequestCondition()
{
$coll = new RouteCollection();
$route = new Route('/foo/{bar}');
$route->setCondition('request.getBaseUrl() == "/sub/front.php" and request.getPathInfo() == "/foo/bar"');
$coll->add('foo', $route);
$matcher = new UrlMatcher($coll, new RequestContext('/sub/front.php'));
$this->assertEquals(array('bar' => 'bar', '_route' => 'foo'), $matcher->match('/foo/bar'));
}
public function testDecodeOnce()
{
$coll = new RouteCollection();