diff --git a/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php b/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php index 5d5a5436d3..be43a72dd2 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php @@ -20,6 +20,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; 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; /** @@ -29,12 +30,16 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; */ 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; } @@ -43,7 +48,7 @@ class RouterListener implements EventSubscriberInterface $request = $event->getRequest(); if (HttpKernelInterface::MASTER_REQUEST === $event->getRequestType()) { - $this->urlMatcher->getContext()->fromRequest($request); + $this->matcher->getContext()->fromRequest($request); } if ($request->attributes->has('_controller')) { @@ -53,7 +58,12 @@ class RouterListener implements EventSubscriberInterface // 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))); diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterListenerTest.php index c33b33dc56..9ac028c652 100644 --- a/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterListenerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterListenerTest.php @@ -77,4 +77,33 @@ class RouterListenerTest extends \PHPUnit_Framework_TestCase 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); + } } diff --git a/src/Symfony/Component/Routing/CHANGELOG.md b/src/Symfony/Component/Routing/CHANGELOG.md index 306708b088..40d6ab1c01 100644 --- a/src/Symfony/Component/Routing/CHANGELOG.md +++ b/src/Symfony/Component/Routing/CHANGELOG.md @@ -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 diff --git a/src/Symfony/Component/Routing/Matcher/RequestMatcherInterface.php b/src/Symfony/Component/Routing/Matcher/RequestMatcherInterface.php new file mode 100644 index 0000000000..6a5c235ac0 --- /dev/null +++ b/src/Symfony/Component/Routing/Matcher/RequestMatcherInterface.php @@ -0,0 +1,40 @@ + + * + * 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 + */ +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); +}