Skip to content
This repository has been archived by the owner on Jul 4, 2018. It is now read-only.

Commit

Permalink
feature #971 [Routing] Replace the UrlMatcher by a RequestMatcher (Gr…
Browse files Browse the repository at this point in the history
…omNaN)

This PR was merged into the 2.0.x-dev branch.

Discussion
----------

[Routing] Replace the UrlMatcher by a RequestMatcher

Commits
-------

857023d [Routing] Replace the UrlMatcher by a RequestMatcher
  • Loading branch information
fabpot committed Sep 16, 2014
2 parents 5775fdb + 857023d commit abb5138
Show file tree
Hide file tree
Showing 8 changed files with 188 additions and 201 deletions.
60 changes: 51 additions & 9 deletions src/Silex/Provider/Locale/LocaleListener.php
Expand Up @@ -13,30 +13,72 @@

use Pimple\Container;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\EventListener\LocaleListener as BaseLocaleListener;
use Symfony\Component\HttpKernel\Event\FinishRequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Routing\RequestContextAwareInterface;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
* Initializes the locale based on the current request.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jérôme Tamarelle <jerome@tamarelle.net>
*/
class LocaleListener extends BaseLocaleListener
class LocaleListener implements EventSubscriberInterface
{
protected $app;
private $app;
private $defaultLocale;
private $requestStack;
private $requestContext;

public function __construct(Container $app, RequestContextAwareInterface $router = null, RequestStack $requestStack = null)
public function __construct(Container $app, $defaultLocale = 'en', RequestStack $requestStack, RequestContext $requestContext = null)
{
parent::__construct($app['locale'], $router, $requestStack);

$this->app = $app;
$this->defaultLocale = $defaultLocale;
$this->requestStack = $requestStack;
$this->requestContext = $requestContext;
}

public function onKernelRequest(GetResponseEvent $event)
{
parent::onKernelRequest($event);
$request = $event->getRequest();
$request->setDefaultLocale($this->defaultLocale);

$this->setLocale($request);
$this->setRouterContext($request);

$this->app['locale'] = $request->getLocale();
}

public function onKernelFinishRequest(FinishRequestEvent $event)
{
if (null !== $parentRequest = $this->requestStack->getParentRequest()) {
$this->setRouterContext($parentRequest);
}
}

private function setLocale(Request $request)
{
if ($locale = $request->attributes->get('_locale')) {
$request->setLocale($locale);
}
}

$this->app['locale'] = $event->getRequest()->getLocale();
private function setRouterContext(Request $request)
{
if (null !== $this->requestContext) {
$this->requestContext->setParameter('_locale', $request->getLocale());
}
}

public static function getSubscribedEvents()
{
return array(
// must be registered after the Router to have access to the _locale
KernelEvents::REQUEST => array(array('onKernelRequest', 16)),
KernelEvents::FINISH_REQUEST => array(array('onKernelFinishRequest', 0)),
);
}
}
10 changes: 1 addition & 9 deletions src/Silex/Provider/LocaleServiceProvider.php
Expand Up @@ -15,7 +15,6 @@
use Pimple\ServiceProviderInterface;
use Silex\Api\EventListenerProviderInterface;
use Silex\Provider\Locale\LocaleListener;
use Silex\Provider\Routing\LazyUrlMatcher;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;

/**
Expand All @@ -28,14 +27,7 @@ class LocaleServiceProvider implements ServiceProviderInterface, EventListenerPr
public function register(Container $app)
{
$app['locale.listener'] = function ($app) {
$urlMatcher = null;
if (isset($app['url_matcher'])) {
$urlMatcher = new LazyUrlMatcher(function () use ($app) {
return $app['url_matcher'];
});
}

return new LocaleListener($app, $urlMatcher, $app['request_stack']);
return new LocaleListener($app, $app['locale'], $app['request_stack'], isset($app['request_context']) ? $app['request_context'] : null);
};

$app['locale'] = 'en';
Expand Down
54 changes: 54 additions & 0 deletions src/Silex/Provider/Routing/LazyRequestMatcher.php
@@ -0,0 +1,54 @@
<?php

/*
* This file is part of the Silex framework.
*
* (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 Silex\Provider\Routing;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Matcher\RequestMatcherInterface;

/**
* Implements a lazy UrlMatcher.
*
* @author Igor Wiedler <igor@wiedler.ch>
* @author Jérôme Tamarelle <jerome@tamarelle.net>
*/
class LazyRequestMatcher implements RequestMatcherInterface
{
private $factory;

public function __construct(\Closure $factory)
{
$this->factory = $factory;
}

/**
* Returns the corresponding RequestMatcherInterface instance.
*
* @return UrlMatcherInterface
*/
public function getRequestMatcher()
{
$matcher = call_user_func($this->factory);
if (!$matcher instanceof RequestMatcherInterface) {
throw new \LogicException("Factory supplied to LazyRequestMatcher must return implementation of Symfony\Component\Routing\RequestMatcherInterface.");
}

return $matcher;
}

/**
* {@inheritdoc}
*/
public function matchRequest(Request $request)
{
return $this->getRequestMatcher()->matchRequest($request);
}
}
69 changes: 0 additions & 69 deletions src/Silex/Provider/Routing/LazyUrlMatcher.php

This file was deleted.

8 changes: 4 additions & 4 deletions src/Silex/Provider/RoutingServiceProvider.php
Expand Up @@ -15,7 +15,7 @@
use Pimple\ServiceProviderInterface;
use Silex\Api\EventListenerProviderInterface;
use Silex\Provider\Routing\RedirectableUrlMatcher;
use Silex\Provider\Routing\LazyUrlMatcher;
use Silex\Provider\Routing\LazyRequestMatcher;
use Symfony\Component\Routing\Generator\UrlGenerator;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\HttpKernel\EventListener\RouterListener;
Expand All @@ -34,7 +34,7 @@ public function register(Container $app)
return new UrlGenerator($app['routes'], $app['request_context']);
};

$app['url_matcher'] = function () use ($app) {
$app['request_matcher'] = function () use ($app) {
return new RedirectableUrlMatcher($app['routes'], $app['request_context']);
};

Expand All @@ -48,8 +48,8 @@ public function register(Container $app)
};

$app['routing.listener'] = function () use ($app) {
$urlMatcher = new LazyUrlMatcher(function () use ($app) {
return $app['url_matcher'];
$urlMatcher = new LazyRequestMatcher(function () use ($app) {
return $app['request_matcher'];
});

return new RouterListener($urlMatcher, $app['request_context'], $app['logger'], $app['request_stack']);
Expand Down
2 changes: 1 addition & 1 deletion src/Silex/Provider/SecurityServiceProvider.php
Expand Up @@ -315,7 +315,7 @@ public function register(Container $app)
};

$app['security.http_utils'] = function ($app) {
return new HttpUtils(isset($app['url_generator']) ? $app['url_generator'] : null, $app['url_matcher']);
return new HttpUtils(isset($app['url_generator']) ? $app['url_generator'] : null, $app['request_matcher']);
};

$app['security.last_error'] = $app->protect(function (Request $request) {
Expand Down
77 changes: 77 additions & 0 deletions tests/Silex/Tests/LazyRequestMatcherTest.php
@@ -0,0 +1,77 @@
<?php

/*
* This file is part of the Silex framework.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace Silex\Tests;

use Symfony\Component\HttpFoundation\Request;
use Silex\Provider\Routing\LazyRequestMatcher;

/**
* LazyRequestMatcher test case.
*
* @author Leszek Prabucki <leszek.prabucki@gmail.com>
*/
class LazyRequestMatcherTest extends \PHPUnit_Framework_TestCase
{
/**
* @covers Silex\LazyRequestMatcher::getResquestMatcher
*/
public function testUserMatcherIsCreatedLazily()
{
$callCounter = 0;
$requestMatcher = $this->getMock('Symfony\Component\Routing\Matcher\RequestMatcherInterface');

$matcher = new LazyRequestMatcher(function () use ($requestMatcher, &$callCounter) {
$callCounter++;

return $requestMatcher;
});

$this->assertEquals(0, $callCounter);
$request = Request::create('path');
$matcher->matchRequest($request);
$this->assertEquals(1, $callCounter);
}

/**
* @expectedException LogicException
* @expectedExceptionMessage Factory supplied to LazyRequestMatcher must return implementation of Symfony\Component\Routing\RequestMatcherInterface.
*/
public function testThatCanInjectResquestMatcherOnly()
{
$matcher = new LazyRequestMatcher(function () {
return 'someMatcher';
});

$request = Request::create('path');
$matcher->matchRequest($request);
}

/**
* @covers Silex\LazyRequestMatcher::matchRequest
*/
public function testMatchIsProxy()
{
$request = Request::create('path');
$matcher = $this->getMock('Symfony\Component\Routing\Matcher\RequestMatcherInterface');
$matcher->expects($this->once())
->method('matchRequest')
->with($request)
->will($this->returnValue('matcherReturnValue'));

$matcher = new LazyRequestMatcher(function () use ($matcher) {
return $matcher;
});
$result = $matcher->matchRequest($request);

$this->assertEquals('matcherReturnValue', $result);
}
}

0 comments on commit abb5138

Please sign in to comment.