Skip to content

Commit

Permalink
[Routing][HttpKernel] Add RequestMatcherInterface.
Browse files Browse the repository at this point in the history
While UrlMatcherInterface is only for matching URLs with routes, add
RequestMatcherInterface, that allows to match against whole requests.
  • Loading branch information
niklasf committed Jun 7, 2012
1 parent 1541fe2 commit 2277500
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 5 deletions.
20 changes: 15 additions & 5 deletions src/Symfony/Component/HttpKernel/EventListener/RouterListener.php
Expand Up @@ -20,6 +20,7 @@
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
Expand All @@ -29,12 +30,16 @@
*/
class RouterListener implements EventSubscriberInterface
{
private $urlMatcher;
private $matcher;
private $logger;

public function __construct(UrlMatcherInterface $urlMatcher, LoggerInterface $logger = null)
public function __construct($matcher, LoggerInterface $logger = null)
{
$this->urlMatcher = $urlMatcher;
if (!$matcher instanceof UrlMatcherInterface && !$matcher instanceof RequestMatcherInterface) {
throw new \InvalidArgumentException('Matcher must either implement UrlMatcherInterface or RequestMatcherInterface.');
}

$this->matcher = $matcher;
$this->logger = $logger;
}

Expand All @@ -43,7 +48,7 @@ public function onKernelRequest(GetResponseEvent $event)
$request = $event->getRequest();

if (HttpKernelInterface::MASTER_REQUEST === $event->getRequestType()) {
$this->urlMatcher->getContext()->fromRequest($request);
$this->matcher->getContext()->fromRequest($request);
}

if ($request->attributes->has('_controller')) {
Expand All @@ -53,7 +58,12 @@ public function onKernelRequest(GetResponseEvent $event)

// add attributes based on the path info (routing)
try {
$parameters = $this->urlMatcher->match($request->getPathInfo());
// matching requests is more powerful than matching URLs only, so try that first
if ($this->matcher instanceof RequestMatcherInterface) {
$parameters = $this->matcher->matchRequest($request);
} else {
$parameters = $this->matcher->match($request->getPathInfo());
}

if (null !== $this->logger) {
$this->logger->info(sprintf('Matched route "%s" (parameters: %s)', $parameters['_route'], $this->parametersToString($parameters)));
Expand Down
Expand Up @@ -77,4 +77,33 @@ private function createGetResponseEventForUri($uri)

return new GetResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST);
}

/**
* @expectedException \InvalidArgumentException
*/
public function testInvalidMatcher()
{
new RouterListener(new \stdClass());
}

public function testRequestMatcher()
{
$kernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface');
$request = Request::create('http://localhost/');
$event = new GetResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST);

$context = new RequestContext();

$requestMatcher = $this->getMock('Symfony\Component\Routing\Matcher\RequestMatcherInterface');
$requestMatcher->expects($this->any())
->method('getContext')
->will($this->returnValue($context));
$requestMatcher->expects($this->once())
->method('matchRequest')
->with($this->isInstanceOf('Symfony\Component\HttpFoundation\Request'))
->will($this->returnValue(array()));

$listener = new RouterListener($requestMatcher);
$listener->onKernelRequest($event);
}
}
1 change: 1 addition & 0 deletions src/Symfony/Component/Routing/CHANGELOG.md
Expand Up @@ -4,6 +4,7 @@ CHANGELOG
2.1.0
-----

* added RequestMatcherInterface
* added RequestContext::fromRequest()
* the UrlMatcher does not throw a \LogicException anymore when the required
scheme is not the current one
Expand Down
40 changes: 40 additions & 0 deletions src/Symfony/Component/Routing/Matcher/RequestMatcherInterface.php
@@ -0,0 +1,40 @@
<?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\Component\Routing\Matcher;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\RequestContextAwareInterface;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
use Symfony\Component\Routing\Exception\MethodNotAllowedException;

/**
* UrlMatcherInterface is the interface that all URL matcher classes must implement.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface RequestMatcherInterface extends RequestContextAwareInterface
{
/**
* Tries to match a request with a set of routes.
*
* If the matcher can not find information, it must throw one of the exceptions documented
* below.
*
* @param Request $request The request to match
*
* @return array An array of parameters
*
* @throws ResourceNotFoundException If no matching resource could be found
* @throws MethodNotAllowedException If a matching resource was found but the request method is not allowed
*/
function matchRequest(Request $request);
}

0 comments on commit 2277500

Please sign in to comment.