From c55f1ea8af80cf5c96b27d57b7bf97843ec73aef Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Thu, 18 Apr 2013 10:33:03 +0200 Subject: [PATCH 1/7] added a RequestStack class --- .../Extension/HttpKernelExtensionTest.php | 39 +++- .../Resources/config/fragment_renderer.xml | 2 +- .../Resources/config/routing.xml | 2 +- .../Resources/config/services.xml | 10 + .../FrameworkBundle/Resources/config/web.xml | 2 +- .../ContainerAwareHttpKernel.php | 7 +- .../HttpKernel/Event/RequestFinishedEvent.php | 21 +++ .../EventListener/LocaleListener.php | 47 +++-- .../EventListener/RouterListener.php | 16 +- .../HttpKernel/Fragment/FragmentHandler.php | 25 +-- .../Component/HttpKernel/HttpKernel.php | 34 +++- .../Component/HttpKernel/KernelEvents.php | 10 + .../Component/HttpKernel/RequestContext.php | 55 ++++++ .../Component/HttpKernel/RequestStack.php | 84 +++++++++ .../ContainerAwareHttpKernelTest.php | 172 +++++++++--------- .../EventListener/LocaleListenerTest.php | 40 +++- .../EventListener/RouterListenerTest.php | 16 +- .../Tests/Fragment/FragmentHandlerTest.php | 20 +- .../HttpKernel/Tests/HttpKernelTest.php | 14 ++ 19 files changed, 477 insertions(+), 139 deletions(-) create mode 100644 src/Symfony/Component/HttpKernel/Event/RequestFinishedEvent.php create mode 100644 src/Symfony/Component/HttpKernel/RequestContext.php create mode 100644 src/Symfony/Component/HttpKernel/RequestStack.php diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php index ce22481921f5a..9739d96ef385e 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php @@ -14,7 +14,9 @@ use Symfony\Bridge\Twig\Extension\HttpKernelExtension; use Symfony\Bridge\Twig\Tests\TestCase; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Fragment\FragmentHandler; +use Symfony\Component\HttpKernel\RequestContext; class HttpKernelExtensionTest extends TestCase { @@ -23,13 +25,30 @@ class HttpKernelExtensionTest extends TestCase */ public function testFragmentWithError() { - $kernel = $this->getFragmentHandler($this->throwException(new \Exception('foo'))); + $renderer = $this->getFragmentHandler($this->throwException(new \Exception('foo'))); - $loader = new \Twig_Loader_Array(array('index' => '{{ fragment("foo") }}')); - $twig = new \Twig_Environment($loader, array('debug' => true, 'cache' => false)); - $twig->addExtension(new HttpKernelExtension($kernel)); + $this->renderTemplate($renderer); + } + + public function testRenderFragment() + { + $renderer = $this->getFragmentHandler($this->returnValue(new Response('html'))); + + $response = $this->renderTemplate($renderer); - $this->renderTemplate($kernel); + $this->assertEquals('html', $response); + } + + public function testUnknownFragmentRenderer() + { + $context = $this->getMockBuilder('Symfony\\Component\\HttpKernel\\RequestContext') + ->disableOriginalConstructor() + ->getMock() + ; + $renderer = new FragmentHandler($context, array()); + + $this->setExpectedException('InvalidArgumentException', 'The "inline" renderer does not exist.'); + $renderer->render('/foo'); } protected function getFragmentHandler($return) @@ -38,8 +57,14 @@ protected function getFragmentHandler($return) $strategy->expects($this->once())->method('getName')->will($this->returnValue('inline')); $strategy->expects($this->once())->method('render')->will($return); - $renderer = new FragmentHandler(array($strategy)); - $renderer->setRequest(Request::create('/')); + $context = $this->getMockBuilder('Symfony\\Component\\HttpKernel\\RequestContext') + ->disableOriginalConstructor() + ->getMock() + ; + + $context->expects($this->any())->method('getCurrentRequest')->will($this->returnValue(Request::create('/'))); + + $renderer = new FragmentHandler($context, array($strategy)); return $renderer; } diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/fragment_renderer.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/fragment_renderer.xml index 4773339906a4e..e613ed11c1d0b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/fragment_renderer.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/fragment_renderer.xml @@ -15,9 +15,9 @@ + %kernel.debug% - diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml index 9e21db4519151..34eb332147490 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml @@ -92,9 +92,9 @@ + - diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml index 674e28f1c98a0..607634d1a7420 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml @@ -12,6 +12,8 @@ Symfony\Component\HttpKernel\CacheClearer\ChainCacheClearer Symfony\Component\HttpKernel\Config\FileLocator Symfony\Component\HttpKernel\UriSigner + Symfony\Component\HttpKernel\RequestStack + Symfony\Component\HttpKernel\RequestContext @@ -23,6 +25,14 @@ + + + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml index 177821a5afb24..d2984f5eb4602 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml @@ -37,8 +37,8 @@ %kernel.default_locale% + - diff --git a/src/Symfony/Component/HttpKernel/DependencyInjection/ContainerAwareHttpKernel.php b/src/Symfony/Component/HttpKernel/DependencyInjection/ContainerAwareHttpKernel.php index c9b8a211d4291..214e3b255dae9 100644 --- a/src/Symfony/Component/HttpKernel/DependencyInjection/ContainerAwareHttpKernel.php +++ b/src/Symfony/Component/HttpKernel/DependencyInjection/ContainerAwareHttpKernel.php @@ -14,6 +14,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\HttpKernel; +use Symfony\Component\HttpKernel\RequestStack; use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -28,6 +29,7 @@ class ContainerAwareHttpKernel extends HttpKernel { protected $container; + protected $requestStack; /** * Constructor. @@ -35,10 +37,11 @@ class ContainerAwareHttpKernel extends HttpKernel * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance * @param ContainerInterface $container A ContainerInterface instance * @param ControllerResolverInterface $controllerResolver A ControllerResolverInterface instance + * @param RequestStack $requestStack A stack for master/sub requests */ - public function __construct(EventDispatcherInterface $dispatcher, ContainerInterface $container, ControllerResolverInterface $controllerResolver) + public function __construct(EventDispatcherInterface $dispatcher, ContainerInterface $container, ControllerResolverInterface $controllerResolver, RequestStack $requestStack) { - parent::__construct($dispatcher, $controllerResolver); + parent::__construct($dispatcher, $controllerResolver, $requestStack); $this->container = $container; diff --git a/src/Symfony/Component/HttpKernel/Event/RequestFinishedEvent.php b/src/Symfony/Component/HttpKernel/Event/RequestFinishedEvent.php new file mode 100644 index 0000000000000..c9d3c39a72cb0 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Event/RequestFinishedEvent.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Event; + +/** + * Triggered whenever a request is fully processed. + * + * @author Benjamin Eberlei + */ +class RequestFinishedEvent extends KernelEvent +{ +} diff --git a/src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php b/src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php index 0b864c02f2bc4..7b6f2ad208ccd 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php @@ -12,7 +12,9 @@ namespace Symfony\Component\HttpKernel\EventListener; use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\HttpKernel\Event\RequestFinishedEvent; use Symfony\Component\HttpKernel\KernelEvents; +use Symfony\Component\HttpKernel\RequestContext; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\RequestContextAwareInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; @@ -26,41 +28,64 @@ class LocaleListener implements EventSubscriberInterface { private $router; private $defaultLocale; + private $requestContext; - public function __construct($defaultLocale = 'en', RequestContextAwareInterface $router = null) + public function __construct($defaultLocale = 'en', RequestContext $requestContext, RequestContextAwareInterface $router = null) { $this->defaultLocale = $defaultLocale; + $this->requestContext = $requestContext; $this->router = $router; } - public function setRequest(Request $request = null) + public function onKernelRequest(GetResponseEvent $event) + { + $request = $event->getRequest(); + $request->setDefaultLocale($this->defaultLocale); + + $this->setLocale($request); + $this->setRouterContext($request); + } + + public function onKernelRequestFinished(RequestFinishedEvent $event) { - if (null === $request) { + $this->resetRouterContext(); + } + + private function resetRouterContext() + { + if ($this->requestContext === null) { + return; + } + + $parentRequest = $this->requestContext->getParentRequest(); + + if ($parentRequest === null) { return; } + $this->setRouterContext($parentRequest); + } + + private function setLocale(Request $request) + { if ($locale = $request->attributes->get('_locale')) { $request->setLocale($locale); } + } + private function setRouterContext(Request $request) + { if (null !== $this->router) { $this->router->getContext()->setParameter('_locale', $request->getLocale()); } } - public function onKernelRequest(GetResponseEvent $event) - { - $request = $event->getRequest(); - $request->setDefaultLocale($this->defaultLocale); - - $this->setRequest($request); - } - 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::REQUEST_FINISHED => array(array('onKernelRequestFinished', 0)), ); } } diff --git a/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php b/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php index 777fd11bf40ab..f2bad02968e69 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php @@ -13,9 +13,11 @@ use Psr\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\HttpKernel\Event\RequestFinishedEvent; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Symfony\Component\HttpKernel\RequestContext as KernelRequestContext; use Symfony\Component\Routing\Exception\MethodNotAllowedException; use Symfony\Component\Routing\Exception\ResourceNotFoundException; use Symfony\Component\Routing\Matcher\UrlMatcherInterface; @@ -36,6 +38,7 @@ class RouterListener implements EventSubscriberInterface private $context; private $logger; private $request; + private $kernelContext; /** * Constructor. @@ -46,7 +49,7 @@ class RouterListener implements EventSubscriberInterface * * @throws \InvalidArgumentException */ - public function __construct($matcher, RequestContext $context = null, LoggerInterface $logger = null) + public function __construct($matcher, KernelRequestContext $kernelContext, RequestContext $context = null, LoggerInterface $logger = null) { if (!$matcher instanceof UrlMatcherInterface && !$matcher instanceof RequestMatcherInterface) { throw new \InvalidArgumentException('Matcher must either implement UrlMatcherInterface or RequestMatcherInterface.'); @@ -58,6 +61,7 @@ public function __construct($matcher, RequestContext $context = null, LoggerInte $this->matcher = $matcher; $this->context = $context ?: $matcher->getContext(); + $this->kernelContext = $kernelContext; $this->logger = $logger; } @@ -71,7 +75,7 @@ public function __construct($matcher, RequestContext $context = null, LoggerInte * * @param Request|null $request A Request instance */ - public function setRequest(Request $request = null) + private function populateRoutingContext(Request $request = null) { if (null !== $request && $this->request !== $request) { $this->context->fromRequest($request); @@ -79,6 +83,11 @@ public function setRequest(Request $request = null) $this->request = $request; } + public function onKernelRequestFinished(RequestFinishedEvent $event) + { + $this->populateRoutingContext($this->kernelContext->getParentRequest()); + } + public function onKernelRequest(GetResponseEvent $event) { $request = $event->getRequest(); @@ -86,7 +95,7 @@ public function onKernelRequest(GetResponseEvent $event) // initialize the context that is also used by the generator (assuming matcher and generator share the same context instance) // we call setRequest even if most of the time, it has already been done to keep compatibility // with frameworks which do not use the Symfony service container - $this->setRequest($request); + $this->populateRoutingContext($request); if ($request->attributes->has('_controller')) { // routing is already done @@ -139,6 +148,7 @@ public static function getSubscribedEvents() { return array( KernelEvents::REQUEST => array(array('onKernelRequest', 32)), + KernelEvents::REQUEST_FINISHED => array(array('onKernelRequestFinished', 0)), ); } } diff --git a/src/Symfony/Component/HttpKernel/Fragment/FragmentHandler.php b/src/Symfony/Component/HttpKernel/Fragment/FragmentHandler.php index af9b9ba98b744..099f35a306bf2 100644 --- a/src/Symfony/Component/HttpKernel/Fragment/FragmentHandler.php +++ b/src/Symfony/Component/HttpKernel/Fragment/FragmentHandler.php @@ -15,6 +15,7 @@ use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\StreamedResponse; use Symfony\Component\HttpKernel\Controller\ControllerReference; +use Symfony\Component\HttpKernel\RequestContext; /** * Renders a URI that represents a resource fragment. @@ -30,7 +31,7 @@ class FragmentHandler { private $debug; private $renderers; - private $request; + private $context; /** * Constructor. @@ -38,8 +39,9 @@ class FragmentHandler * @param FragmentRendererInterface[] $renderers An array of FragmentRendererInterface instances * @param Boolean $debug Whether the debug mode is enabled or not */ - public function __construct(array $renderers = array(), $debug = false) + public function __construct(RequestContext $context, array $renderers = array(), $debug = false) { + $this->context = $context; $this->renderers = array(); foreach ($renderers as $renderer) { $this->addRenderer($renderer); @@ -57,16 +59,6 @@ public function addRenderer(FragmentRendererInterface $renderer) $this->renderers[$renderer->getName()] = $renderer; } - /** - * Sets the current Request. - * - * @param Request $request The current Request - */ - public function setRequest(Request $request = null) - { - $this->request = $request; - } - /** * Renders a URI and returns the Response content. * @@ -93,11 +85,7 @@ public function render($uri, $renderer = 'inline', array $options = array()) throw new \InvalidArgumentException(sprintf('The "%s" renderer does not exist.', $renderer)); } - if (null === $this->request) { - throw new \LogicException('Rendering a fragment can only be done when handling a master Request.'); - } - - return $this->deliver($this->renderers[$renderer]->render($uri, $this->request, $options)); + return $this->deliver($this->renderers[$renderer]->render($uri, $this->context->getCurrentRequest(), $options)); } /** @@ -115,7 +103,8 @@ public function render($uri, $renderer = 'inline', array $options = array()) protected function deliver(Response $response) { if (!$response->isSuccessful()) { - throw new \RuntimeException(sprintf('Error when rendering "%s" (Status code is %s).', $this->request->getUri(), $response->getStatusCode())); + $request = $this->context->getCurrentRequest(); + throw new \RuntimeException(sprintf('Error when rendering "%s" (Status code is %s).', $request->getUri(), $response->getStatusCode())); } if (!$response instanceof StreamedResponse) { diff --git a/src/Symfony/Component/HttpKernel/HttpKernel.php b/src/Symfony/Component/HttpKernel/HttpKernel.php index 837a16ff370e9..71c1b91fc8acf 100644 --- a/src/Symfony/Component/HttpKernel/HttpKernel.php +++ b/src/Symfony/Component/HttpKernel/HttpKernel.php @@ -16,6 +16,7 @@ use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; use Symfony\Component\HttpKernel\Event\FilterControllerEvent; use Symfony\Component\HttpKernel\Event\FilterResponseEvent; +use Symfony\Component\HttpKernel\Event\RequestFinishedEvent; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent; use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; @@ -35,19 +36,22 @@ class HttpKernel implements HttpKernelInterface, TerminableInterface { protected $dispatcher; protected $resolver; + protected $requestStack; /** * Constructor * - * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance - * @param ControllerResolverInterface $resolver A ControllerResolverInterface instance + * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance + * @param ControllerResolverInterface $resolver A ControllerResolverInterface instance + * @param RequestStack $requestStack A stack for master/sub requests * * @api */ - public function __construct(EventDispatcherInterface $dispatcher, ControllerResolverInterface $resolver) + public function __construct(EventDispatcherInterface $dispatcher, ControllerResolverInterface $resolver, RequestStack $requestStack = null) { $this->dispatcher = $dispatcher; $this->resolver = $resolver; + $this->requestStack = $requestStack ?: new RequestStack(); } /** @@ -60,6 +64,8 @@ public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQ try { return $this->handleRaw($request, $type); } catch (\Exception $e) { + $this->finishRequest($request, $type); + if (false === $catch) { throw $e; } @@ -93,6 +99,8 @@ public function terminate(Request $request, Response $response) */ private function handleRaw(Request $request, $type = self::MASTER_REQUEST) { + $this->requestStack->push($request); + // request $event = new GetResponseEvent($this, $request, $type); $this->dispatcher->dispatch(KernelEvents::REQUEST, $event); @@ -156,9 +164,29 @@ private function filterResponse(Response $response, Request $request, $type) $this->dispatcher->dispatch(KernelEvents::RESPONSE, $event); + $this->finishRequest($request, $type); + return $event->getResponse(); } + /** + * Publish event finished event, then pop the request from the stack. + * + * Note: Order of the operations is important here, otherwise operations + * such as {@link RequestStack::getParentRequest()} can lead to weird + * results. + * + * @param Request $request + * @param int $type + * + * @return void + */ + private function finishRequest(Request $request, $type) + { + $this->dispatcher->dispatch(KernelEvents::REQUEST_FINISHED, new RequestFinishedEvent($this, $request, $type)); + $this->requestStack->pop(); + } + /** * Handles an exception by trying to convert it to a Response. * diff --git a/src/Symfony/Component/HttpKernel/KernelEvents.php b/src/Symfony/Component/HttpKernel/KernelEvents.php index fce48ac3a6ed8..e1ad0fa004fe3 100644 --- a/src/Symfony/Component/HttpKernel/KernelEvents.php +++ b/src/Symfony/Component/HttpKernel/KernelEvents.php @@ -102,4 +102,14 @@ final class KernelEvents * @var string */ const TERMINATE = 'kernel.terminate'; + + /** + * The REQUEST_FINISHED event occurs when a response was generated for a request. + * + * This event allows you to reset the global and environmental state of + * the application, when it was changed during the request. + * + * @var string + */ + const REQUEST_FINISHED = 'kernel.request_finished'; } diff --git a/src/Symfony/Component/HttpKernel/RequestContext.php b/src/Symfony/Component/HttpKernel/RequestContext.php new file mode 100644 index 0000000000000..f6fdaf3bbe834 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/RequestContext.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel; + +/** + * Registry for Requests. + * + * Facade for RequestStack that prevents modification of the stack, + * so that users don't accidentally push()/pop() from the stack and + * mess up the request cycle. + * + * @author Benjamin Eberlei + */ +class RequestContext +{ + private $stack; + + public function __construct(RequestStack $stack) + { + $this->stack = $stack; + } + + /** + * @return Request + */ + public function getCurrentRequest() + { + return $this->stack->getCurrentRequest(); + } + + /** + * @return Request + */ + public function getMasterRequest() + { + return $this->stack->getMasterRequest(); + } + + /** + * @return Request|null + */ + public function getParentRequest() + { + return $this->stack->getParentRequest(); + } +} diff --git a/src/Symfony/Component/HttpKernel/RequestStack.php b/src/Symfony/Component/HttpKernel/RequestStack.php new file mode 100644 index 0000000000000..c8de54981d937 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/RequestStack.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel; + +use Symfony\Component\HttpFoundation\Request; + +/** + * Request stack that controls the lifecycle of requests. + * + * Notifies services of changes in the stack. + * + * @author Benjamin Eberlei + */ +class RequestStack +{ + /** + * @var Request[] + */ + private $requests = array(); + + public function push(Request $request) + { + $this->requests[] = $request; + } + + /** + * Pop the current request from the stack. + * + * This operation lets the current request go out of scope. + * + * @return Request + */ + public function pop() + { + return array_pop($this->requests); + } + + /** + * @return Request|null + */ + public function getCurrentRequest() + { + return end($this->requests) ?: null; + } + + /** + * @return Request|null + */ + public function getMasterRequest() + { + if (!$this->requests) { + return null; + } + + return $this->requests[0]; + } + + /** + * Return the parent request of the current. + * + * If current Request is the master request, method returns null. + * + * @return Request + */ + public function getParentRequest() + { + $pos = count($this->requests) - 2; + + if (!isset($this->requests[$pos])) { + return null; + } + + return $this->requests[$pos]; + } +} diff --git a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/ContainerAwareHttpKernelTest.php b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/ContainerAwareHttpKernelTest.php index 28901dafdd643..292a5e9f45d18 100644 --- a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/ContainerAwareHttpKernelTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/ContainerAwareHttpKernelTest.php @@ -13,6 +13,7 @@ use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\DependencyInjection\ContainerAwareHttpKernel; +use Symfony\Component\HttpKernel\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\EventDispatcher\EventDispatcher; @@ -26,59 +27,49 @@ public function testHandle($type) { $request = new Request(); $expected = new Response(); + $controller = function() use ($expected) { + return $expected; + }; $container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface'); - $container - ->expects($this->once()) - ->method('enterScope') - ->with($this->equalTo('request')) - ; - $container - ->expects($this->once()) - ->method('leaveScope') - ->with($this->equalTo('request')) - ; - $container - ->expects($this->at(0)) - ->method('hasScope') - ->with($this->equalTo('request')) - ->will($this->returnValue(false)); - $container - ->expects($this->at(1)) - ->method('addScope') - ->with($this->isInstanceOf('Symfony\Component\DependencyInjection\Scope')); - // enterScope() - $container - ->expects($this->at(3)) - ->method('set') - ->with($this->equalTo('request'), $this->equalTo($request), $this->equalTo('request')) - ; - $container - ->expects($this->at(4)) - ->method('set') - ->with($this->equalTo('request'), $this->equalTo(null), $this->equalTo('request')) + $this + ->expectsEnterScopeOnce($container) + ->expectsLeaveScopeOnce($container) + ->expectsSetRequestWithAt($container, $request, 3) + ->expectsSetRequestWithAt($container, null, 4) ; $dispatcher = new EventDispatcher(); - $resolver = $this->getMock('Symfony\\Component\\HttpKernel\\Controller\\ControllerResolverInterface'); - $kernel = new ContainerAwareHttpKernel($dispatcher, $container, $resolver); + $resolver = $this->getResolverMockFor($controller, $request); + $stack = new RequestStack(); + $kernel = new ContainerAwareHttpKernel($dispatcher, $container, $resolver, $stack); - $controller = function () use ($expected) { + $actual = $kernel->handle($request, $type); + + $this->assertSame($expected, $actual, '->handle() returns the response'); + } + + /** + * @dataProvider getProviderTypes + */ + public function testVerifyRequestStackPushPopDuringHandle($type) + { + $request = new Request(); + $expected = new Response(); + $controller = function() use ($expected) { return $expected; }; - $resolver->expects($this->once()) - ->method('getController') - ->with($request) - ->will($this->returnValue($controller)); - $resolver->expects($this->once()) - ->method('getArguments') - ->with($request, $controller) - ->will($this->returnValue(array())); + $stack = $this->getMock('Symfony\Component\HttpKernel\RequestStack', array('push', 'pop')); + $stack->expects($this->at(0))->method('push')->with($this->equalTo($request)); + $stack->expects($this->at(1))->method('pop'); - $actual = $kernel->handle($request, $type); + $container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface'); + $dispatcher = new EventDispatcher(); + $resolver = $this->getResolverMockFor($controller, $request); + $kernel = new ContainerAwareHttpKernel($dispatcher, $container, $resolver, $stack); - $this->assertSame($expected, $actual, '->handle() returns the response'); + $kernel->handle($request, $type); } /** @@ -88,51 +79,23 @@ public function testHandleRestoresThePreviousRequestOnException($type) { $request = new Request(); $expected = new \Exception(); + $controller = function() use ($expected) { + throw $expected; + }; $container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface'); - $container - ->expects($this->once()) - ->method('enterScope') - ->with($this->equalTo('request')) - ; - $container - ->expects($this->once()) - ->method('leaveScope') - ->with($this->equalTo('request')) - ; - $container - ->expects($this->at(0)) - ->method('hasScope') - ->with($this->equalTo('request')) - ->will($this->returnValue(true)); - // enterScope() - $container - ->expects($this->at(2)) - ->method('set') - ->with($this->equalTo('request'), $this->equalTo($request), $this->equalTo('request')) - ; - $container - ->expects($this->at(3)) - ->method('set') - ->with($this->equalTo('request'), $this->equalTo(null), $this->equalTo('request')) + $this + ->expectsEnterScopeOnce($container) + ->expectsLeaveScopeOnce($container) + ->expectsSetRequestWithAt($container, $request, 3) + ->expectsSetRequestWithAt($container, null, 4) ; $dispatcher = new EventDispatcher(); $resolver = $this->getMock('Symfony\\Component\\HttpKernel\\Controller\\ControllerResolverInterface'); - $kernel = new ContainerAwareHttpKernel($dispatcher, $container, $resolver); - - $controller = function () use ($expected) { - throw $expected; - }; - - $resolver->expects($this->once()) - ->method('getController') - ->with($request) - ->will($this->returnValue($controller)); - $resolver->expects($this->once()) - ->method('getArguments') - ->with($request, $controller) - ->will($this->returnValue(array())); + $resolver = $this->getResolverMockFor($controller, $request); + $stack = new RequestStack(); + $kernel = new ContainerAwareHttpKernel($dispatcher, $container, $resolver, $stack); try { $kernel->handle($request, $type); @@ -151,4 +114,51 @@ public function getProviderTypes() array(HttpKernelInterface::SUB_REQUEST), ); } + + private function getResolverMockFor($controller, $request) + { + $resolver = $this->getMock('Symfony\\Component\\HttpKernel\\Controller\\ControllerResolverInterface'); + $resolver->expects($this->once()) + ->method('getController') + ->with($request) + ->will($this->returnValue($controller)); + $resolver->expects($this->once()) + ->method('getArguments') + ->with($request, $controller) + ->will($this->returnValue(array())); + + return $resolver; + } + + private function expectsSetRequestWithAt($container, $with, $at) + { + $container + ->expects($this->at($at)) + ->method('set') + ->with($this->equalTo('request'), $this->equalTo($with), $this->equalTo('request')) + ; + return $this; + } + + private function expectsEnterScopeOnce($container) + { + $container + ->expects($this->once()) + ->method('enterScope') + ->with($this->equalTo('request')) + ; + + return $this; + } + + private function expectsLeaveScopeOnce($container) + { + $container + ->expects($this->once()) + ->method('leaveScope') + ->with($this->equalTo('request')) + ; + + return $this; + } } diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php index 36859baa16b0f..2cdfec93de453 100644 --- a/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php @@ -12,15 +12,23 @@ namespace Symfony\Component\HttpKernel\Tests\EventListener; use Symfony\Component\HttpKernel\EventListener\LocaleListener; +use Symfony\Component\HttpKernel\RequestContext; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; class LocaleListenerTest extends \PHPUnit_Framework_TestCase { + private $context; + + protected function setUp() + { + $this->context = $this->getMock('Symfony\Component\HttpKernel\RequestContext', array(), array(), '', false); + } + public function testDefaultLocaleWithoutSession() { - $listener = new LocaleListener('fr'); + $listener = new LocaleListener('fr', $this->context); $event = $this->getEvent($request = Request::create('/')); $listener->onKernelRequest($event); @@ -34,7 +42,7 @@ public function testLocaleFromRequestAttribute() $request->cookies->set('foo', 'value'); $request->attributes->set('_locale', 'es'); - $listener = new LocaleListener('fr'); + $listener = new LocaleListener('fr', $this->context); $event = $this->getEvent($request); $listener->onKernelRequest($event); @@ -53,15 +61,39 @@ public function testLocaleSetForRoutingContext() $request = Request::create('/'); $request->attributes->set('_locale', 'es'); - $listener = new LocaleListener('fr', $router); + $listener = new LocaleListener('fr', $this->context, $router); $listener->onKernelRequest($this->getEvent($request)); } + public function testRouterResetWithParentRequestOnKernelRequestFinished() + { + if (!class_exists('Symfony\Component\Routing\Router')) { + $this->markTestSkipped('The "Routing" component is not available'); + } + + // the request context is updated + $context = $this->getMock('Symfony\Component\Routing\RequestContext'); + $context->expects($this->once())->method('setParameter')->with('_locale', 'es'); + + $router = $this->getMock('Symfony\Component\Routing\Router', array('getContext'), array(), '', false); + $router->expects($this->once())->method('getContext')->will($this->returnValue($context)); + + $parentRequest = Request::create('/'); + $parentRequest->setLocale('es'); + + $this->context->expects($this->once())->method('getParentRequest')->will($this->returnValue($parentRequest)); + + $event = $this->getMock('Symfony\Component\HttpKernel\Event\RequestFinishedEvent', array(), array(), '', false); + + $listener = new LocaleListener('fr', $this->context, $router); + $listener->onKernelRequestFinished($event); + } + public function testRequestLocaleIsNotOverridden() { $request = Request::create('/'); $request->setLocale('de'); - $listener = new LocaleListener('fr'); + $listener = new LocaleListener('fr', $this->context); $event = $this->getEvent($request); $listener->onKernelRequest($event); diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterListenerTest.php index 66fe6bd55d505..2bd1810dca46d 100644 --- a/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterListenerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterListenerTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\HttpKernel\Tests\EventListener; use Symfony\Component\HttpKernel\EventListener\RouterListener; +use Symfony\Component\HttpKernel\RequestContext as KernelRequestContext; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; @@ -19,6 +20,13 @@ class RouterListenerTest extends \PHPUnit_Framework_TestCase { + private $kernelContext; + + public function setUp() + { + $this->kernelContext = $this->getMock('Symfony\Component\HttpKernel\RequestContext', array(), array(), '', false); + } + /** * @dataProvider getPortData */ @@ -34,7 +42,7 @@ public function testPort($defaultHttpPort, $defaultHttpsPort, $uri, $expectedHtt ->method('getContext') ->will($this->returnValue($context)); - $listener = new RouterListener($urlMatcher); + $listener = new RouterListener($urlMatcher, $this->kernelContext); $event = $this->createGetResponseEventForUri($uri); $listener->onKernelRequest($event); @@ -72,7 +80,7 @@ private function createGetResponseEventForUri($uri) */ public function testInvalidMatcher() { - new RouterListener(new \stdClass()); + new RouterListener(new \stdClass(), $this->kernelContext); } public function testRequestMatcher() @@ -87,7 +95,7 @@ public function testRequestMatcher() ->with($this->isInstanceOf('Symfony\Component\HttpFoundation\Request')) ->will($this->returnValue(array())); - $listener = new RouterListener($requestMatcher, new RequestContext()); + $listener = new RouterListener($requestMatcher, $this->kernelContext, new RequestContext()); $listener->onKernelRequest($event); } @@ -108,7 +116,7 @@ public function testSubRequestWithDifferentMethod() ->method('getContext') ->will($this->returnValue($context)); - $listener = new RouterListener($requestMatcher, new RequestContext()); + $listener = new RouterListener($requestMatcher, $this->kernelContext, new RequestContext()); $listener->onKernelRequest($event); // sub-request with another HTTP method diff --git a/src/Symfony/Component/HttpKernel/Tests/Fragment/FragmentHandlerTest.php b/src/Symfony/Component/HttpKernel/Tests/Fragment/FragmentHandlerTest.php index cec8ae98403a7..33e01d54b3970 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Fragment/FragmentHandlerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Fragment/FragmentHandlerTest.php @@ -17,12 +17,27 @@ class FragmentHandlerTest extends \PHPUnit_Framework_TestCase { + private $context; + + public function setUp() + { + $this->context = $this->getMockBuilder('Symfony\\Component\\HttpKernel\\RequestContext') + ->disableOriginalConstructor() + ->getMock() + ; + $this->context + ->expects($this->any()) + ->method('getCurrentRequest') + ->will($this->returnValue(Request::create('/'))) + ; + } + /** * @expectedException \InvalidArgumentException */ public function testRenderWhenRendererDoesNotExist() { - $handler = new FragmentHandler(); + $handler = new FragmentHandler($this->context); $handler->render('/', 'foo'); } @@ -72,9 +87,8 @@ protected function getHandler($returnValue, $arguments = array()) call_user_func_array(array($e, 'with'), $arguments); } - $handler = new FragmentHandler(); + $handler = new FragmentHandler($this->context); $handler->addRenderer($renderer); - $handler->setRequest(Request::create('/')); return $handler; } diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php index 1bfa0e5fa822e..120e945cd60b1 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php @@ -238,6 +238,20 @@ public function testTerminate() $this->assertEquals($response, $capturedResponse); } + public function testVerifyRequestStackPushPopDuringHandle() + { + $request = new Request(); + + $stack = $this->getMock('Symfony\Component\HttpKernel\RequestStack', array('push', 'pop')); + $stack->expects($this->at(0))->method('push')->with($this->equalTo($request)); + $stack->expects($this->at(1))->method('pop'); + + $dispatcher = new EventDispatcher(); + $kernel = new HttpKernel($dispatcher, $this->getResolver(), $stack); + + $kernel->handle($request, HttpKernelInterface::MASTER_REQUEST); + } + protected function getResolver($controller = null) { if (null === $controller) { From a58a8a69fd7e6922547a827037d182e29fb13211 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 31 Aug 2013 21:46:39 +0200 Subject: [PATCH 2/7] [HttpKernel] changed request_stack to a private service --- .../Bundle/FrameworkBundle/Resources/config/services.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml index 607634d1a7420..3bcbe16d628c1 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml @@ -28,7 +28,7 @@ - + From f9b10ba1d5715832fd12a930e282abdb3b2ea462 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 31 Aug 2013 22:02:11 +0200 Subject: [PATCH 3/7] [HttpKernel] renamed the kernel finished event --- .../{RequestFinishedEvent.php => FinishRequestEvent.php} | 2 +- .../Component/HttpKernel/EventListener/LocaleListener.php | 6 +++--- .../Component/HttpKernel/EventListener/RouterListener.php | 6 +++--- src/Symfony/Component/HttpKernel/HttpKernel.php | 4 ++-- src/Symfony/Component/HttpKernel/KernelEvents.php | 2 +- .../HttpKernel/Tests/EventListener/LocaleListenerTest.php | 6 +++--- 6 files changed, 13 insertions(+), 13 deletions(-) rename src/Symfony/Component/HttpKernel/Event/{RequestFinishedEvent.php => FinishRequestEvent.php} (89%) diff --git a/src/Symfony/Component/HttpKernel/Event/RequestFinishedEvent.php b/src/Symfony/Component/HttpKernel/Event/FinishRequestEvent.php similarity index 89% rename from src/Symfony/Component/HttpKernel/Event/RequestFinishedEvent.php rename to src/Symfony/Component/HttpKernel/Event/FinishRequestEvent.php index c9d3c39a72cb0..ee724843cd843 100644 --- a/src/Symfony/Component/HttpKernel/Event/RequestFinishedEvent.php +++ b/src/Symfony/Component/HttpKernel/Event/FinishRequestEvent.php @@ -16,6 +16,6 @@ * * @author Benjamin Eberlei */ -class RequestFinishedEvent extends KernelEvent +class FinishRequestEvent extends KernelEvent { } diff --git a/src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php b/src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php index 7b6f2ad208ccd..2dd16a479c7bf 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php @@ -12,7 +12,7 @@ namespace Symfony\Component\HttpKernel\EventListener; use Symfony\Component\HttpKernel\Event\GetResponseEvent; -use Symfony\Component\HttpKernel\Event\RequestFinishedEvent; +use Symfony\Component\HttpKernel\Event\FinishRequestEvent; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\RequestContext; use Symfony\Component\HttpFoundation\Request; @@ -46,7 +46,7 @@ public function onKernelRequest(GetResponseEvent $event) $this->setRouterContext($request); } - public function onKernelRequestFinished(RequestFinishedEvent $event) + public function onKernelFinishRequest(FinishRequestEvent $event) { $this->resetRouterContext(); } @@ -85,7 +85,7 @@ 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::REQUEST_FINISHED => array(array('onKernelRequestFinished', 0)), + KernelEvents::FINISH_REQUEST => array(array('onKernelFinishRequest', 0)), ); } } diff --git a/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php b/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php index f2bad02968e69..a09ec648d1b26 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php @@ -13,7 +13,7 @@ use Psr\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; -use Symfony\Component\HttpKernel\Event\RequestFinishedEvent; +use Symfony\Component\HttpKernel\Event\FinishRequestEvent; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -83,7 +83,7 @@ private function populateRoutingContext(Request $request = null) $this->request = $request; } - public function onKernelRequestFinished(RequestFinishedEvent $event) + public function onKernelFinishRequest(FinishRequestEvent $event) { $this->populateRoutingContext($this->kernelContext->getParentRequest()); } @@ -148,7 +148,7 @@ public static function getSubscribedEvents() { return array( KernelEvents::REQUEST => array(array('onKernelRequest', 32)), - KernelEvents::REQUEST_FINISHED => array(array('onKernelRequestFinished', 0)), + KernelEvents::FINISH_REQUEST => array(array('onKernelFinishRequest', 0)), ); } } diff --git a/src/Symfony/Component/HttpKernel/HttpKernel.php b/src/Symfony/Component/HttpKernel/HttpKernel.php index 71c1b91fc8acf..511d942b654b5 100644 --- a/src/Symfony/Component/HttpKernel/HttpKernel.php +++ b/src/Symfony/Component/HttpKernel/HttpKernel.php @@ -16,7 +16,7 @@ use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; use Symfony\Component\HttpKernel\Event\FilterControllerEvent; use Symfony\Component\HttpKernel\Event\FilterResponseEvent; -use Symfony\Component\HttpKernel\Event\RequestFinishedEvent; +use Symfony\Component\HttpKernel\Event\FinishRequestEvent; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent; use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; @@ -183,7 +183,7 @@ private function filterResponse(Response $response, Request $request, $type) */ private function finishRequest(Request $request, $type) { - $this->dispatcher->dispatch(KernelEvents::REQUEST_FINISHED, new RequestFinishedEvent($this, $request, $type)); + $this->dispatcher->dispatch(KernelEvents::FINISH_REQUEST, new FinishRequestEvent($this, $request, $type)); $this->requestStack->pop(); } diff --git a/src/Symfony/Component/HttpKernel/KernelEvents.php b/src/Symfony/Component/HttpKernel/KernelEvents.php index e1ad0fa004fe3..5e6ebcb8d9926 100644 --- a/src/Symfony/Component/HttpKernel/KernelEvents.php +++ b/src/Symfony/Component/HttpKernel/KernelEvents.php @@ -111,5 +111,5 @@ final class KernelEvents * * @var string */ - const REQUEST_FINISHED = 'kernel.request_finished'; + const FINISH_REQUEST = 'kernel.finish_request'; } diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php index 2cdfec93de453..eb82ebeb1cb6a 100644 --- a/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php @@ -65,7 +65,7 @@ public function testLocaleSetForRoutingContext() $listener->onKernelRequest($this->getEvent($request)); } - public function testRouterResetWithParentRequestOnKernelRequestFinished() + public function testRouterResetWithParentRequestOnKernelFinishRequest() { if (!class_exists('Symfony\Component\Routing\Router')) { $this->markTestSkipped('The "Routing" component is not available'); @@ -83,10 +83,10 @@ public function testRouterResetWithParentRequestOnKernelRequestFinished() $this->context->expects($this->once())->method('getParentRequest')->will($this->returnValue($parentRequest)); - $event = $this->getMock('Symfony\Component\HttpKernel\Event\RequestFinishedEvent', array(), array(), '', false); + $event = $this->getMock('Symfony\Component\HttpKernel\Event\FinishRequestEvent', array(), array(), '', false); $listener = new LocaleListener('fr', $this->context, $router); - $listener->onKernelRequestFinished($event); + $listener->onKernelFinishRequest($event); } public function testRequestLocaleIsNotOverridden() From 018b71936f077f59da748021be9b48f876d04e53 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 31 Aug 2013 22:10:38 +0200 Subject: [PATCH 4/7] [HttpKernel] tweaked the code --- .../ContainerAwareHttpKernel.php | 4 +- .../EventListener/LocaleListener.php | 38 +++++++++++-------- .../EventListener/RouterListener.php | 21 +++++----- .../HttpKernel/Fragment/FragmentHandler.php | 7 +++- .../Component/HttpKernel/HttpKernel.php | 18 ++++----- .../Component/HttpKernel/RequestContext.php | 4 +- .../Component/HttpKernel/RequestStack.php | 14 ++++--- 7 files changed, 60 insertions(+), 46 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/DependencyInjection/ContainerAwareHttpKernel.php b/src/Symfony/Component/HttpKernel/DependencyInjection/ContainerAwareHttpKernel.php index 214e3b255dae9..c7fea3be7b43f 100644 --- a/src/Symfony/Component/HttpKernel/DependencyInjection/ContainerAwareHttpKernel.php +++ b/src/Symfony/Component/HttpKernel/DependencyInjection/ContainerAwareHttpKernel.php @@ -37,9 +37,9 @@ class ContainerAwareHttpKernel extends HttpKernel * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance * @param ContainerInterface $container A ContainerInterface instance * @param ControllerResolverInterface $controllerResolver A ControllerResolverInterface instance - * @param RequestStack $requestStack A stack for master/sub requests + * @param RequestStack $requestStack A stack for master/sub requests */ - public function __construct(EventDispatcherInterface $dispatcher, ContainerInterface $container, ControllerResolverInterface $controllerResolver, RequestStack $requestStack) + public function __construct(EventDispatcherInterface $dispatcher, ContainerInterface $container, ControllerResolverInterface $controllerResolver, RequestStack $requestStack = null) { parent::__construct($dispatcher, $controllerResolver, $requestStack); diff --git a/src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php b/src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php index 2dd16a479c7bf..4bfbf9cb5e977 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php @@ -37,6 +37,27 @@ public function __construct($defaultLocale = 'en', RequestContext $requestContex $this->router = $router; } + /** + * Sets the current Request. + * + * This method was used to synchronize the Request, but as the HttpKernel + * is doing that automatically now, you should never be called it directly. + * It is kept public for BC with the 2.3 version. + * + * @param Request|null $request A Request instance + * + * @deprecated Deprecated since version 2.4, to be removed in 3.0. + */ + public function setRequest(Request $request = null) + { + if (null === $request) { + return; + } + + $this->setLocale($request); + $this->setRouterContext($request); + } + public function onKernelRequest(GetResponseEvent $event) { $request = $event->getRequest(); @@ -48,22 +69,9 @@ public function onKernelRequest(GetResponseEvent $event) public function onKernelFinishRequest(FinishRequestEvent $event) { - $this->resetRouterContext(); - } - - private function resetRouterContext() - { - if ($this->requestContext === null) { - return; - } - - $parentRequest = $this->requestContext->getParentRequest(); - - if ($parentRequest === null) { - return; + if (null !== $parentRequest = $this->requestContext->getParentRequest()) { + $this->setRouterContext($parentRequest); } - - $this->setRouterContext($parentRequest); } private function setLocale(Request $request) diff --git a/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php b/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php index a09ec648d1b26..8c94f23a430d4 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php @@ -68,14 +68,15 @@ public function __construct($matcher, KernelRequestContext $kernelContext, Reque /** * Sets the current Request. * - * The application should call this method whenever the Request - * object changes (entering a Request scope for instance, but - * also when leaving a Request scope -- especially when they are - * nested). + * This method was used to synchronize the Request, but as the HttpKernel + * is doing that automatically now, you should never be called it directly. + * It is kept public for BC with the 2.3 version. * * @param Request|null $request A Request instance + * + * @deprecated Deprecated since version 2.4, to be moved to a private function in 3.0. */ - private function populateRoutingContext(Request $request = null) + public function setRequest(Request $request = null) { if (null !== $request && $this->request !== $request) { $this->context->fromRequest($request); @@ -83,10 +84,10 @@ private function populateRoutingContext(Request $request = null) $this->request = $request; } - public function onKernelFinishRequest(FinishRequestEvent $event) - { - $this->populateRoutingContext($this->kernelContext->getParentRequest()); - } + public function onKernelFinishRequest(FinishRequestEvent $event) + { + $this->setRequest($this->kernelContext->getParentRequest()); + } public function onKernelRequest(GetResponseEvent $event) { @@ -95,7 +96,7 @@ public function onKernelRequest(GetResponseEvent $event) // initialize the context that is also used by the generator (assuming matcher and generator share the same context instance) // we call setRequest even if most of the time, it has already been done to keep compatibility // with frameworks which do not use the Symfony service container - $this->populateRoutingContext($request); + $this->setRequest($request); if ($request->attributes->has('_controller')) { // routing is already done diff --git a/src/Symfony/Component/HttpKernel/Fragment/FragmentHandler.php b/src/Symfony/Component/HttpKernel/Fragment/FragmentHandler.php index 099f35a306bf2..d54daea9235df 100644 --- a/src/Symfony/Component/HttpKernel/Fragment/FragmentHandler.php +++ b/src/Symfony/Component/HttpKernel/Fragment/FragmentHandler.php @@ -85,6 +85,10 @@ public function render($uri, $renderer = 'inline', array $options = array()) throw new \InvalidArgumentException(sprintf('The "%s" renderer does not exist.', $renderer)); } + if (null === $this->context->getCurrentRequest()) { + throw new \LogicException('Rendering a fragment can only be done when handling a Request.'); + } + return $this->deliver($this->renderers[$renderer]->render($uri, $this->context->getCurrentRequest(), $options)); } @@ -103,8 +107,7 @@ public function render($uri, $renderer = 'inline', array $options = array()) protected function deliver(Response $response) { if (!$response->isSuccessful()) { - $request = $this->context->getCurrentRequest(); - throw new \RuntimeException(sprintf('Error when rendering "%s" (Status code is %s).', $request->getUri(), $response->getStatusCode())); + throw new \RuntimeException(sprintf('Error when rendering "%s" (Status code is %s).', $this->context->getCurrentRequest()->getUri(), $response->getStatusCode())); } if (!$response instanceof StreamedResponse) { diff --git a/src/Symfony/Component/HttpKernel/HttpKernel.php b/src/Symfony/Component/HttpKernel/HttpKernel.php index 511d942b654b5..7ac5316adf8f0 100644 --- a/src/Symfony/Component/HttpKernel/HttpKernel.php +++ b/src/Symfony/Component/HttpKernel/HttpKernel.php @@ -64,9 +64,9 @@ public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQ try { return $this->handleRaw($request, $type); } catch (\Exception $e) { - $this->finishRequest($request, $type); - if (false === $catch) { + $this->finishRequest($request, $type); + throw $e; } @@ -170,16 +170,14 @@ private function filterResponse(Response $response, Request $request, $type) } /** - * Publish event finished event, then pop the request from the stack. + * Publishes the finish request event, then pop the request from the stack. * - * Note: Order of the operations is important here, otherwise operations - * such as {@link RequestStack::getParentRequest()} can lead to weird - * results. + * Note that the order of the operations is important here, otherwise + * operations such as {@link RequestStack::getParentRequest()} can lead to + * weird results. * * @param Request $request - * @param int $type - * - * @return void + * @param int $type */ private function finishRequest(Request $request, $type) { @@ -207,6 +205,8 @@ private function handleException(\Exception $e, $request, $type) $e = $event->getException(); if (!$event->hasResponse()) { + $this->finishRequest($request, $type); + throw $e; } diff --git a/src/Symfony/Component/HttpKernel/RequestContext.php b/src/Symfony/Component/HttpKernel/RequestContext.php index f6fdaf3bbe834..de8aacc3e5819 100644 --- a/src/Symfony/Component/HttpKernel/RequestContext.php +++ b/src/Symfony/Component/HttpKernel/RequestContext.php @@ -30,7 +30,7 @@ public function __construct(RequestStack $stack) } /** - * @return Request + * @return Request|null */ public function getCurrentRequest() { @@ -38,7 +38,7 @@ public function getCurrentRequest() } /** - * @return Request + * @return Request|null */ public function getMasterRequest() { diff --git a/src/Symfony/Component/HttpKernel/RequestStack.php b/src/Symfony/Component/HttpKernel/RequestStack.php index c8de54981d937..40e37718b7d11 100644 --- a/src/Symfony/Component/HttpKernel/RequestStack.php +++ b/src/Symfony/Component/HttpKernel/RequestStack.php @@ -16,8 +16,6 @@ /** * Request stack that controls the lifecycle of requests. * - * Notifies services of changes in the stack. - * * @author Benjamin Eberlei */ class RequestStack @@ -33,7 +31,7 @@ public function push(Request $request) } /** - * Pop the current request from the stack. + * Pops the current request from the stack. * * This operation lets the current request go out of scope. * @@ -41,6 +39,10 @@ public function push(Request $request) */ public function pop() { + if (!$this->requests) { + throw new \LogicException('Unable to pop a Request as the stack is already empty.'); + } + return array_pop($this->requests); } @@ -65,11 +67,11 @@ public function getMasterRequest() } /** - * Return the parent request of the current. + * Returns the parent request of the current. * - * If current Request is the master request, method returns null. + * If current Request is the master request, it returns null. * - * @return Request + * @return Request|null */ public function getParentRequest() { From 93e60eaeabe74f11371cbf7597ab4d7026f260f3 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 7 Sep 2013 20:20:07 +0200 Subject: [PATCH 5/7] [HttpKernel] modified listeners to be BC with Symfony <2.4 --- .../Extension/HttpKernelExtensionTest.php | 4 +- .../Resources/config/fragment_renderer.xml | 2 +- .../Resources/config/routing.xml | 2 +- .../FrameworkBundle/Resources/config/web.xml | 2 +- .../EventListener/LocaleListener.php | 14 ++++++- .../EventListener/RouterListener.php | 18 ++++++++- .../HttpKernel/Fragment/FragmentHandler.php | 37 +++++++++++++++++-- .../EventListener/LocaleListenerTest.php | 10 ++--- .../EventListener/RouterListenerTest.php | 8 ++-- .../Tests/Fragment/FragmentHandlerTest.php | 4 +- 10 files changed, 78 insertions(+), 23 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php index 9739d96ef385e..445bb036da4ae 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php @@ -45,7 +45,7 @@ public function testUnknownFragmentRenderer() ->disableOriginalConstructor() ->getMock() ; - $renderer = new FragmentHandler($context, array()); + $renderer = new FragmentHandler(array(), false, $context); $this->setExpectedException('InvalidArgumentException', 'The "inline" renderer does not exist.'); $renderer->render('/foo'); @@ -64,7 +64,7 @@ protected function getFragmentHandler($return) $context->expects($this->any())->method('getCurrentRequest')->will($this->returnValue(Request::create('/'))); - $renderer = new FragmentHandler($context, array($strategy)); + $renderer = new FragmentHandler(array($strategy), false, $context); return $renderer; } diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/fragment_renderer.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/fragment_renderer.xml index e613ed11c1d0b..27fff103fc0fc 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/fragment_renderer.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/fragment_renderer.xml @@ -15,9 +15,9 @@ - %kernel.debug% + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml index 34eb332147490..5db144e814fe4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml @@ -92,9 +92,9 @@ - + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml index d2984f5eb4602..3f6e455aab660 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml @@ -37,8 +37,8 @@ %kernel.default_locale% - + diff --git a/src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php b/src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php index 4bfbf9cb5e977..2170376b98048 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php @@ -22,6 +22,11 @@ /** * Initializes the locale based on the current request. * + * This listener works in 2 modes: + * + * * 2.3 compatibility mode where you must call setRequest whenever the Request changes. + * * 2.4+ mode where you must pass a RequestContext instance in the constructor. + * * @author Fabien Potencier */ class LocaleListener implements EventSubscriberInterface @@ -30,7 +35,10 @@ class LocaleListener implements EventSubscriberInterface private $defaultLocale; private $requestContext; - public function __construct($defaultLocale = 'en', RequestContext $requestContext, RequestContextAwareInterface $router = null) + /** + * RequestContext will become required in 3.0. + */ + public function __construct($defaultLocale = 'en', RequestContextAwareInterface $router = null, RequestContext $requestContext = null) { $this->defaultLocale = $defaultLocale; $this->requestContext = $requestContext; @@ -69,6 +77,10 @@ public function onKernelRequest(GetResponseEvent $event) public function onKernelFinishRequest(FinishRequestEvent $event) { + if (null === $this->requestContext) { + throw new \LogicException('You must pass a RequestContext.'); + } + if (null !== $parentRequest = $this->requestContext->getParentRequest()) { $this->setRouterContext($parentRequest); } diff --git a/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php b/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php index 8c94f23a430d4..5ed590d4570bf 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php @@ -30,6 +30,11 @@ /** * Initializes the context from the request and sets request attributes based on a matching route. * + * This listener works in 2 modes: + * + * * 2.3 compatibility mode where you must call setRequest whenever the Request changes. + * * 2.4+ mode where you must pass a RequestContext instance in the constructor. + * * @author Fabien Potencier */ class RouterListener implements EventSubscriberInterface @@ -43,13 +48,15 @@ class RouterListener implements EventSubscriberInterface /** * Constructor. * + * RequestContext will become required in 3.0. + * * @param UrlMatcherInterface|RequestMatcherInterface $matcher The Url or Request matcher * @param RequestContext|null $context The RequestContext (can be null when $matcher implements RequestContextAwareInterface) * @param LoggerInterface|null $logger The logger * * @throws \InvalidArgumentException */ - public function __construct($matcher, KernelRequestContext $kernelContext, RequestContext $context = null, LoggerInterface $logger = null) + public function __construct($matcher, RequestContext $context = null, LoggerInterface $logger = null, KernelRequestContext $kernelContext = null) { if (!$matcher instanceof UrlMatcherInterface && !$matcher instanceof RequestMatcherInterface) { throw new \InvalidArgumentException('Matcher must either implement UrlMatcherInterface or RequestMatcherInterface.'); @@ -86,6 +93,10 @@ public function setRequest(Request $request = null) public function onKernelFinishRequest(FinishRequestEvent $event) { + if (null === $this->kernelContext) { + throw new \LogicException('You must pass a RequestContext.'); + } + $this->setRequest($this->kernelContext->getParentRequest()); } @@ -96,7 +107,10 @@ public function onKernelRequest(GetResponseEvent $event) // initialize the context that is also used by the generator (assuming matcher and generator share the same context instance) // we call setRequest even if most of the time, it has already been done to keep compatibility // with frameworks which do not use the Symfony service container - $this->setRequest($request); + // when we have a RequestContext, no need to do it + if (null !== $this->kernelContext) { + $this->setRequest($request); + } if ($request->attributes->has('_controller')) { // routing is already done diff --git a/src/Symfony/Component/HttpKernel/Fragment/FragmentHandler.php b/src/Symfony/Component/HttpKernel/Fragment/FragmentHandler.php index d54daea9235df..d7cc5d182791b 100644 --- a/src/Symfony/Component/HttpKernel/Fragment/FragmentHandler.php +++ b/src/Symfony/Component/HttpKernel/Fragment/FragmentHandler.php @@ -23,6 +23,11 @@ * This class handles the rendering of resource fragments that are included into * a main resource. The handling of the rendering is managed by specialized renderers. * + * This listener works in 2 modes: + * + * * 2.3 compatibility mode where you must call setRequest whenever the Request changes. + * * 2.4+ mode where you must pass a RequestContext instance in the constructor. + * * @author Fabien Potencier * * @see FragmentRendererInterface @@ -31,15 +36,18 @@ class FragmentHandler { private $debug; private $renderers; + private $request; private $context; /** * Constructor. * + * RequestContext will become required in 3.0. + * * @param FragmentRendererInterface[] $renderers An array of FragmentRendererInterface instances * @param Boolean $debug Whether the debug mode is enabled or not */ - public function __construct(RequestContext $context, array $renderers = array(), $debug = false) + public function __construct(array $renderers = array(), $debug = false, RequestContext $context = null) { $this->context = $context; $this->renderers = array(); @@ -59,6 +67,22 @@ public function addRenderer(FragmentRendererInterface $renderer) $this->renderers[$renderer->getName()] = $renderer; } + /** + * Sets the current Request. + * + * This method was used to synchronize the Request, but as the HttpKernel + * is doing that automatically now, you should never be called it directly. + * It is kept public for BC with the 2.3 version. + * + * @param Request|null $request A Request instance + * + * @deprecated Deprecated since version 2.4, to be removed in 3.0. + */ + public function setRequest(Request $request = null) + { + $this->request = $request; + } + /** * Renders a URI and returns the Response content. * @@ -85,11 +109,11 @@ public function render($uri, $renderer = 'inline', array $options = array()) throw new \InvalidArgumentException(sprintf('The "%s" renderer does not exist.', $renderer)); } - if (null === $this->context->getCurrentRequest()) { + if (!$request = $this->getRequest()) { throw new \LogicException('Rendering a fragment can only be done when handling a Request.'); } - return $this->deliver($this->renderers[$renderer]->render($uri, $this->context->getCurrentRequest(), $options)); + return $this->deliver($this->renderers[$renderer]->render($uri, $request, $options)); } /** @@ -107,7 +131,7 @@ public function render($uri, $renderer = 'inline', array $options = array()) protected function deliver(Response $response) { if (!$response->isSuccessful()) { - throw new \RuntimeException(sprintf('Error when rendering "%s" (Status code is %s).', $this->context->getCurrentRequest()->getUri(), $response->getStatusCode())); + throw new \RuntimeException(sprintf('Error when rendering "%s" (Status code is %s).', $this->getRequest()->getUri(), $response->getStatusCode())); } if (!$response instanceof StreamedResponse) { @@ -116,4 +140,9 @@ protected function deliver(Response $response) $response->sendContent(); } + + private function getRequest() + { + return $this->context ? $this->context->getCurrentRequest() : $this->request; + } } diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php index eb82ebeb1cb6a..270a11d295180 100644 --- a/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php @@ -28,7 +28,7 @@ protected function setUp() public function testDefaultLocaleWithoutSession() { - $listener = new LocaleListener('fr', $this->context); + $listener = new LocaleListener('fr', null, $this->context); $event = $this->getEvent($request = Request::create('/')); $listener->onKernelRequest($event); @@ -42,7 +42,7 @@ public function testLocaleFromRequestAttribute() $request->cookies->set('foo', 'value'); $request->attributes->set('_locale', 'es'); - $listener = new LocaleListener('fr', $this->context); + $listener = new LocaleListener('fr', null, $this->context); $event = $this->getEvent($request); $listener->onKernelRequest($event); @@ -61,7 +61,7 @@ public function testLocaleSetForRoutingContext() $request = Request::create('/'); $request->attributes->set('_locale', 'es'); - $listener = new LocaleListener('fr', $this->context, $router); + $listener = new LocaleListener('fr', $router, $this->context); $listener->onKernelRequest($this->getEvent($request)); } @@ -85,7 +85,7 @@ public function testRouterResetWithParentRequestOnKernelFinishRequest() $event = $this->getMock('Symfony\Component\HttpKernel\Event\FinishRequestEvent', array(), array(), '', false); - $listener = new LocaleListener('fr', $this->context, $router); + $listener = new LocaleListener('fr', $router, $this->context); $listener->onKernelFinishRequest($event); } @@ -93,7 +93,7 @@ public function testRequestLocaleIsNotOverridden() { $request = Request::create('/'); $request->setLocale('de'); - $listener = new LocaleListener('fr', $this->context); + $listener = new LocaleListener('fr', null, $this->context); $event = $this->getEvent($request); $listener->onKernelRequest($event); diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterListenerTest.php index 2bd1810dca46d..07be703f87ff9 100644 --- a/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterListenerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterListenerTest.php @@ -42,7 +42,7 @@ public function testPort($defaultHttpPort, $defaultHttpsPort, $uri, $expectedHtt ->method('getContext') ->will($this->returnValue($context)); - $listener = new RouterListener($urlMatcher, $this->kernelContext); + $listener = new RouterListener($urlMatcher, null, null, $this->kernelContext); $event = $this->createGetResponseEventForUri($uri); $listener->onKernelRequest($event); @@ -80,7 +80,7 @@ private function createGetResponseEventForUri($uri) */ public function testInvalidMatcher() { - new RouterListener(new \stdClass(), $this->kernelContext); + new RouterListener(new \stdClass(), null, null, $this->kernelContext); } public function testRequestMatcher() @@ -95,7 +95,7 @@ public function testRequestMatcher() ->with($this->isInstanceOf('Symfony\Component\HttpFoundation\Request')) ->will($this->returnValue(array())); - $listener = new RouterListener($requestMatcher, $this->kernelContext, new RequestContext()); + $listener = new RouterListener($requestMatcher, new RequestContext(), null, $this->kernelContext); $listener->onKernelRequest($event); } @@ -116,7 +116,7 @@ public function testSubRequestWithDifferentMethod() ->method('getContext') ->will($this->returnValue($context)); - $listener = new RouterListener($requestMatcher, $this->kernelContext, new RequestContext()); + $listener = new RouterListener($requestMatcher, new RequestContext(), null, $this->kernelContext); $listener->onKernelRequest($event); // sub-request with another HTTP method diff --git a/src/Symfony/Component/HttpKernel/Tests/Fragment/FragmentHandlerTest.php b/src/Symfony/Component/HttpKernel/Tests/Fragment/FragmentHandlerTest.php index 33e01d54b3970..1ea7b50c3374d 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Fragment/FragmentHandlerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Fragment/FragmentHandlerTest.php @@ -37,7 +37,7 @@ public function setUp() */ public function testRenderWhenRendererDoesNotExist() { - $handler = new FragmentHandler($this->context); + $handler = new FragmentHandler(array(), null, $this->context); $handler->render('/', 'foo'); } @@ -87,7 +87,7 @@ protected function getHandler($returnValue, $arguments = array()) call_user_func_array(array($e, 'with'), $arguments); } - $handler = new FragmentHandler($this->context); + $handler = new FragmentHandler(array(), null, $this->context); $handler->addRenderer($renderer); return $handler; From b1a062d232866164ae5112c702ceab361213ce44 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 7 Sep 2013 22:38:41 +0200 Subject: [PATCH 6/7] moved RequestStack to HttpFoundation and removed RequestContext --- .../Extension/HttpKernelExtensionTest.php | 6 +- .../Resources/config/fragment_renderer.xml | 2 +- .../Resources/config/routing.xml | 2 +- .../Resources/config/services.xml | 10 +--- .../FrameworkBundle/Resources/config/web.xml | 2 +- .../Component/HttpFoundation/CHANGELOG.md | 1 + .../RequestStack.php | 23 +++++++- src/Symfony/Component/HttpKernel/CHANGELOG.md | 5 ++ .../ContainerAwareHttpKernel.php | 3 +- .../EventListener/LocaleListener.php | 18 +++--- .../EventListener/RouterListener.php | 22 ++++---- .../HttpKernel/Fragment/FragmentHandler.php | 14 ++--- .../Component/HttpKernel/HttpKernel.php | 1 + .../Component/HttpKernel/RequestContext.php | 55 ------------------- .../ContainerAwareHttpKernelTest.php | 4 +- .../EventListener/LocaleListenerTest.php | 20 +++---- .../EventListener/RouterListenerTest.php | 16 +++--- .../Tests/Fragment/FragmentHandlerTest.php | 10 ++-- .../HttpKernel/Tests/HttpKernelTest.php | 2 +- .../Component/HttpKernel/composer.json | 2 +- 20 files changed, 90 insertions(+), 128 deletions(-) rename src/Symfony/Component/{HttpKernel => HttpFoundation}/RequestStack.php (68%) delete mode 100644 src/Symfony/Component/HttpKernel/RequestContext.php diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php index 445bb036da4ae..8ce564265ec9d 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php @@ -15,8 +15,8 @@ use Symfony\Bridge\Twig\Tests\TestCase; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Fragment\FragmentHandler; -use Symfony\Component\HttpKernel\RequestContext; class HttpKernelExtensionTest extends TestCase { @@ -41,7 +41,7 @@ public function testRenderFragment() public function testUnknownFragmentRenderer() { - $context = $this->getMockBuilder('Symfony\\Component\\HttpKernel\\RequestContext') + $context = $this->getMockBuilder('Symfony\\Component\\HttpFoundation\\RequestStack') ->disableOriginalConstructor() ->getMock() ; @@ -57,7 +57,7 @@ protected function getFragmentHandler($return) $strategy->expects($this->once())->method('getName')->will($this->returnValue('inline')); $strategy->expects($this->once())->method('render')->will($return); - $context = $this->getMockBuilder('Symfony\\Component\\HttpKernel\\RequestContext') + $context = $this->getMockBuilder('Symfony\\Component\\HttpFoundation\\RequestStack') ->disableOriginalConstructor() ->getMock() ; diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/fragment_renderer.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/fragment_renderer.xml index 27fff103fc0fc..a1beee30a1fb8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/fragment_renderer.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/fragment_renderer.xml @@ -17,7 +17,7 @@ %kernel.debug% - + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml index 5db144e814fe4..6b2f7c9688699 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml @@ -94,7 +94,7 @@ - + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml index 3bcbe16d628c1..608bf42d5253f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml @@ -12,8 +12,7 @@ Symfony\Component\HttpKernel\CacheClearer\ChainCacheClearer Symfony\Component\HttpKernel\Config\FileLocator Symfony\Component\HttpKernel\UriSigner - Symfony\Component\HttpKernel\RequestStack - Symfony\Component\HttpKernel\RequestContext + Symfony\Component\HttpFoundation\RequestStack @@ -28,12 +27,7 @@ - - - - - - + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml index 3f6e455aab660..6c1dd73e2e615 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml @@ -38,7 +38,7 @@ %kernel.default_locale% - + diff --git a/src/Symfony/Component/HttpFoundation/CHANGELOG.md b/src/Symfony/Component/HttpFoundation/CHANGELOG.md index 954b66ac43c02..061d47e7eec94 100644 --- a/src/Symfony/Component/HttpFoundation/CHANGELOG.md +++ b/src/Symfony/Component/HttpFoundation/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 2.4.0 ----- + * added RequestStack * added Request::getEncodings() * added accessors methods to session handlers diff --git a/src/Symfony/Component/HttpKernel/RequestStack.php b/src/Symfony/Component/HttpFoundation/RequestStack.php similarity index 68% rename from src/Symfony/Component/HttpKernel/RequestStack.php rename to src/Symfony/Component/HttpFoundation/RequestStack.php index 40e37718b7d11..71bfd106991f8 100644 --- a/src/Symfony/Component/HttpKernel/RequestStack.php +++ b/src/Symfony/Component/HttpFoundation/RequestStack.php @@ -9,9 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\HttpKernel; - -use Symfony\Component\HttpFoundation\Request; +namespace Symfony\Component\HttpFoundation; /** * Request stack that controls the lifecycle of requests. @@ -25,6 +23,12 @@ class RequestStack */ private $requests = array(); + /** + * Pushes a Request on the stack. + * + * This method should generally not be called directly as the stack + * management should be taken care of by the application itself. + */ public function push(Request $request) { $this->requests[] = $request; @@ -35,6 +39,9 @@ public function push(Request $request) * * This operation lets the current request go out of scope. * + * This method should generally not be called directly as the stack + * management should be taken care of by the application itself. + * * @return Request */ public function pop() @@ -55,6 +62,12 @@ public function getCurrentRequest() } /** + * Gets the master Request. + * + * Be warned that making your code aware of the master request + * might make it un-compatible with other features of your framework + * like ESI support. + * * @return Request|null */ public function getMasterRequest() @@ -69,6 +82,10 @@ public function getMasterRequest() /** * Returns the parent request of the current. * + * Be warned that making your code aware of the parent request + * might make it un-compatible with other features of your framework + * like ESI support. + * * If current Request is the master request, it returns null. * * @return Request|null diff --git a/src/Symfony/Component/HttpKernel/CHANGELOG.md b/src/Symfony/Component/HttpKernel/CHANGELOG.md index c06dd3fa57e07..b36e9358ff13e 100644 --- a/src/Symfony/Component/HttpKernel/CHANGELOG.md +++ b/src/Symfony/Component/HttpKernel/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +2.4.0 +----- + + * added the KernelEvents::FINISH_REQUEST event + 2.3.0 ----- diff --git a/src/Symfony/Component/HttpKernel/DependencyInjection/ContainerAwareHttpKernel.php b/src/Symfony/Component/HttpKernel/DependencyInjection/ContainerAwareHttpKernel.php index c7fea3be7b43f..69e7937d18c11 100644 --- a/src/Symfony/Component/HttpKernel/DependencyInjection/ContainerAwareHttpKernel.php +++ b/src/Symfony/Component/HttpKernel/DependencyInjection/ContainerAwareHttpKernel.php @@ -12,9 +12,9 @@ namespace Symfony\Component\HttpKernel\DependencyInjection; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\HttpKernel; -use Symfony\Component\HttpKernel\RequestStack; use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -29,7 +29,6 @@ class ContainerAwareHttpKernel extends HttpKernel { protected $container; - protected $requestStack; /** * Constructor. diff --git a/src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php b/src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php index 2170376b98048..7cab6aa39b560 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php @@ -14,7 +14,7 @@ use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\Event\FinishRequestEvent; use Symfony\Component\HttpKernel\KernelEvents; -use Symfony\Component\HttpKernel\RequestContext; +use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\RequestContextAwareInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; @@ -25,7 +25,7 @@ * This listener works in 2 modes: * * * 2.3 compatibility mode where you must call setRequest whenever the Request changes. - * * 2.4+ mode where you must pass a RequestContext instance in the constructor. + * * 2.4+ mode where you must pass a RequestStack instance in the constructor. * * @author Fabien Potencier */ @@ -33,15 +33,15 @@ class LocaleListener implements EventSubscriberInterface { private $router; private $defaultLocale; - private $requestContext; + private $requestStack; /** - * RequestContext will become required in 3.0. + * RequestStack will become required in 3.0. */ - public function __construct($defaultLocale = 'en', RequestContextAwareInterface $router = null, RequestContext $requestContext = null) + public function __construct($defaultLocale = 'en', RequestContextAwareInterface $router = null, RequestStack $requestStack = null) { $this->defaultLocale = $defaultLocale; - $this->requestContext = $requestContext; + $this->requestStack = $requestStack; $this->router = $router; } @@ -77,11 +77,11 @@ public function onKernelRequest(GetResponseEvent $event) public function onKernelFinishRequest(FinishRequestEvent $event) { - if (null === $this->requestContext) { - throw new \LogicException('You must pass a RequestContext.'); + if (null === $this->requestStack) { + throw new \LogicException('You must pass a RequestStack.'); } - if (null !== $parentRequest = $this->requestContext->getParentRequest()) { + if (null !== $parentRequest = $this->requestStack->getParentRequest()) { $this->setRouterContext($parentRequest); } } diff --git a/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php b/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php index 5ed590d4570bf..d122388b4b086 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php @@ -17,7 +17,7 @@ use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; -use Symfony\Component\HttpKernel\RequestContext as KernelRequestContext; +use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Routing\Exception\MethodNotAllowedException; use Symfony\Component\Routing\Exception\ResourceNotFoundException; use Symfony\Component\Routing\Matcher\UrlMatcherInterface; @@ -33,7 +33,7 @@ * This listener works in 2 modes: * * * 2.3 compatibility mode where you must call setRequest whenever the Request changes. - * * 2.4+ mode where you must pass a RequestContext instance in the constructor. + * * 2.4+ mode where you must pass a RequestStack instance in the constructor. * * @author Fabien Potencier */ @@ -43,12 +43,12 @@ class RouterListener implements EventSubscriberInterface private $context; private $logger; private $request; - private $kernelContext; + private $requestStack; /** * Constructor. * - * RequestContext will become required in 3.0. + * RequestStack will become required in 3.0. * * @param UrlMatcherInterface|RequestMatcherInterface $matcher The Url or Request matcher * @param RequestContext|null $context The RequestContext (can be null when $matcher implements RequestContextAwareInterface) @@ -56,7 +56,7 @@ class RouterListener implements EventSubscriberInterface * * @throws \InvalidArgumentException */ - public function __construct($matcher, RequestContext $context = null, LoggerInterface $logger = null, KernelRequestContext $kernelContext = null) + public function __construct($matcher, RequestContext $context = null, LoggerInterface $logger = null, RequestStack $requestStack = null) { if (!$matcher instanceof UrlMatcherInterface && !$matcher instanceof RequestMatcherInterface) { throw new \InvalidArgumentException('Matcher must either implement UrlMatcherInterface or RequestMatcherInterface.'); @@ -68,7 +68,7 @@ public function __construct($matcher, RequestContext $context = null, LoggerInte $this->matcher = $matcher; $this->context = $context ?: $matcher->getContext(); - $this->kernelContext = $kernelContext; + $this->requestStack = $requestStack; $this->logger = $logger; } @@ -93,11 +93,11 @@ public function setRequest(Request $request = null) public function onKernelFinishRequest(FinishRequestEvent $event) { - if (null === $this->kernelContext) { - throw new \LogicException('You must pass a RequestContext.'); + if (null === $this->requestStack) { + throw new \LogicException('You must pass a RequestStack.'); } - $this->setRequest($this->kernelContext->getParentRequest()); + $this->setRequest($this->requestStack->getParentRequest()); } public function onKernelRequest(GetResponseEvent $event) @@ -107,8 +107,8 @@ public function onKernelRequest(GetResponseEvent $event) // initialize the context that is also used by the generator (assuming matcher and generator share the same context instance) // we call setRequest even if most of the time, it has already been done to keep compatibility // with frameworks which do not use the Symfony service container - // when we have a RequestContext, no need to do it - if (null !== $this->kernelContext) { + // when we have a RequestStack, no need to do it + if (null !== $this->requestStack) { $this->setRequest($request); } diff --git a/src/Symfony/Component/HttpKernel/Fragment/FragmentHandler.php b/src/Symfony/Component/HttpKernel/Fragment/FragmentHandler.php index d7cc5d182791b..05b6a086e9709 100644 --- a/src/Symfony/Component/HttpKernel/Fragment/FragmentHandler.php +++ b/src/Symfony/Component/HttpKernel/Fragment/FragmentHandler.php @@ -14,8 +14,8 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\StreamedResponse; +use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Controller\ControllerReference; -use Symfony\Component\HttpKernel\RequestContext; /** * Renders a URI that represents a resource fragment. @@ -26,7 +26,7 @@ * This listener works in 2 modes: * * * 2.3 compatibility mode where you must call setRequest whenever the Request changes. - * * 2.4+ mode where you must pass a RequestContext instance in the constructor. + * * 2.4+ mode where you must pass a RequestStack instance in the constructor. * * @author Fabien Potencier * @@ -37,19 +37,19 @@ class FragmentHandler private $debug; private $renderers; private $request; - private $context; + private $requestStack; /** * Constructor. * - * RequestContext will become required in 3.0. + * RequestStack will become required in 3.0. * * @param FragmentRendererInterface[] $renderers An array of FragmentRendererInterface instances * @param Boolean $debug Whether the debug mode is enabled or not */ - public function __construct(array $renderers = array(), $debug = false, RequestContext $context = null) + public function __construct(array $renderers = array(), $debug = false, RequestStack $requestStack = null) { - $this->context = $context; + $this->requestStack = $requestStack; $this->renderers = array(); foreach ($renderers as $renderer) { $this->addRenderer($renderer); @@ -143,6 +143,6 @@ protected function deliver(Response $response) private function getRequest() { - return $this->context ? $this->context->getCurrentRequest() : $this->request; + return $this->requestStack ? $this->requestStack->getCurrentRequest() : $this->request; } } diff --git a/src/Symfony/Component/HttpKernel/HttpKernel.php b/src/Symfony/Component/HttpKernel/HttpKernel.php index 7ac5316adf8f0..0be8e1b4dbb7c 100644 --- a/src/Symfony/Component/HttpKernel/HttpKernel.php +++ b/src/Symfony/Component/HttpKernel/HttpKernel.php @@ -22,6 +22,7 @@ use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; use Symfony\Component\HttpKernel\Event\PostResponseEvent; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\EventDispatcher\EventDispatcherInterface; diff --git a/src/Symfony/Component/HttpKernel/RequestContext.php b/src/Symfony/Component/HttpKernel/RequestContext.php deleted file mode 100644 index de8aacc3e5819..0000000000000 --- a/src/Symfony/Component/HttpKernel/RequestContext.php +++ /dev/null @@ -1,55 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel; - -/** - * Registry for Requests. - * - * Facade for RequestStack that prevents modification of the stack, - * so that users don't accidentally push()/pop() from the stack and - * mess up the request cycle. - * - * @author Benjamin Eberlei - */ -class RequestContext -{ - private $stack; - - public function __construct(RequestStack $stack) - { - $this->stack = $stack; - } - - /** - * @return Request|null - */ - public function getCurrentRequest() - { - return $this->stack->getCurrentRequest(); - } - - /** - * @return Request|null - */ - public function getMasterRequest() - { - return $this->stack->getMasterRequest(); - } - - /** - * @return Request|null - */ - public function getParentRequest() - { - return $this->stack->getParentRequest(); - } -} diff --git a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/ContainerAwareHttpKernelTest.php b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/ContainerAwareHttpKernelTest.php index 292a5e9f45d18..2c8a6a28ec149 100644 --- a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/ContainerAwareHttpKernelTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/ContainerAwareHttpKernelTest.php @@ -13,7 +13,7 @@ use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\DependencyInjection\ContainerAwareHttpKernel; -use Symfony\Component\HttpKernel\RequestStack; +use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\EventDispatcher\EventDispatcher; @@ -60,7 +60,7 @@ public function testVerifyRequestStackPushPopDuringHandle($type) return $expected; }; - $stack = $this->getMock('Symfony\Component\HttpKernel\RequestStack', array('push', 'pop')); + $stack = $this->getMock('Symfony\Component\HttpFoundation\RequestStack', array('push', 'pop')); $stack->expects($this->at(0))->method('push')->with($this->equalTo($request)); $stack->expects($this->at(1))->method('pop'); diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php index 270a11d295180..d128753ffab06 100644 --- a/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php @@ -11,24 +11,24 @@ namespace Symfony\Component\HttpKernel\Tests\EventListener; -use Symfony\Component\HttpKernel\EventListener\LocaleListener; -use Symfony\Component\HttpKernel\RequestContext; +use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\EventListener\LocaleListener; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; class LocaleListenerTest extends \PHPUnit_Framework_TestCase { - private $context; + private $requestStack; protected function setUp() { - $this->context = $this->getMock('Symfony\Component\HttpKernel\RequestContext', array(), array(), '', false); + $this->requestStack = $this->getMock('Symfony\Component\HttpFoundation\RequestStack', array(), array(), '', false); } public function testDefaultLocaleWithoutSession() { - $listener = new LocaleListener('fr', null, $this->context); + $listener = new LocaleListener('fr', null, $this->requestStack); $event = $this->getEvent($request = Request::create('/')); $listener->onKernelRequest($event); @@ -42,7 +42,7 @@ public function testLocaleFromRequestAttribute() $request->cookies->set('foo', 'value'); $request->attributes->set('_locale', 'es'); - $listener = new LocaleListener('fr', null, $this->context); + $listener = new LocaleListener('fr', null, $this->requestStack); $event = $this->getEvent($request); $listener->onKernelRequest($event); @@ -61,7 +61,7 @@ public function testLocaleSetForRoutingContext() $request = Request::create('/'); $request->attributes->set('_locale', 'es'); - $listener = new LocaleListener('fr', $router, $this->context); + $listener = new LocaleListener('fr', $router, $this->requestStack); $listener->onKernelRequest($this->getEvent($request)); } @@ -81,11 +81,11 @@ public function testRouterResetWithParentRequestOnKernelFinishRequest() $parentRequest = Request::create('/'); $parentRequest->setLocale('es'); - $this->context->expects($this->once())->method('getParentRequest')->will($this->returnValue($parentRequest)); + $this->requestStack->expects($this->once())->method('getParentRequest')->will($this->returnValue($parentRequest)); $event = $this->getMock('Symfony\Component\HttpKernel\Event\FinishRequestEvent', array(), array(), '', false); - $listener = new LocaleListener('fr', $router, $this->context); + $listener = new LocaleListener('fr', $router, $this->requestStack); $listener->onKernelFinishRequest($event); } @@ -93,7 +93,7 @@ public function testRequestLocaleIsNotOverridden() { $request = Request::create('/'); $request->setLocale('de'); - $listener = new LocaleListener('fr', null, $this->context); + $listener = new LocaleListener('fr', null, $this->requestStack); $event = $this->getEvent($request); $listener->onKernelRequest($event); diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterListenerTest.php index 07be703f87ff9..ac742b35e08ce 100644 --- a/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterListenerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterListenerTest.php @@ -11,20 +11,20 @@ namespace Symfony\Component\HttpKernel\Tests\EventListener; -use Symfony\Component\HttpKernel\EventListener\RouterListener; -use Symfony\Component\HttpKernel\RequestContext as KernelRequestContext; +use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\EventListener\RouterListener; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\Routing\RequestContext; class RouterListenerTest extends \PHPUnit_Framework_TestCase { - private $kernelContext; + private $requestStack; public function setUp() { - $this->kernelContext = $this->getMock('Symfony\Component\HttpKernel\RequestContext', array(), array(), '', false); + $this->requestStack = $this->getMock('Symfony\Component\HttpFoundation\RequestStack', array(), array(), '', false); } /** @@ -42,7 +42,7 @@ public function testPort($defaultHttpPort, $defaultHttpsPort, $uri, $expectedHtt ->method('getContext') ->will($this->returnValue($context)); - $listener = new RouterListener($urlMatcher, null, null, $this->kernelContext); + $listener = new RouterListener($urlMatcher, null, null, $this->requestStack); $event = $this->createGetResponseEventForUri($uri); $listener->onKernelRequest($event); @@ -80,7 +80,7 @@ private function createGetResponseEventForUri($uri) */ public function testInvalidMatcher() { - new RouterListener(new \stdClass(), null, null, $this->kernelContext); + new RouterListener(new \stdClass(), null, null, $this->requestStack); } public function testRequestMatcher() @@ -95,7 +95,7 @@ public function testRequestMatcher() ->with($this->isInstanceOf('Symfony\Component\HttpFoundation\Request')) ->will($this->returnValue(array())); - $listener = new RouterListener($requestMatcher, new RequestContext(), null, $this->kernelContext); + $listener = new RouterListener($requestMatcher, new RequestContext(), null, $this->requestStack); $listener->onKernelRequest($event); } @@ -116,7 +116,7 @@ public function testSubRequestWithDifferentMethod() ->method('getContext') ->will($this->returnValue($context)); - $listener = new RouterListener($requestMatcher, new RequestContext(), null, $this->kernelContext); + $listener = new RouterListener($requestMatcher, new RequestContext(), null, $this->requestStack); $listener->onKernelRequest($event); // sub-request with another HTTP method diff --git a/src/Symfony/Component/HttpKernel/Tests/Fragment/FragmentHandlerTest.php b/src/Symfony/Component/HttpKernel/Tests/Fragment/FragmentHandlerTest.php index 1ea7b50c3374d..dbf6b20b424ed 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Fragment/FragmentHandlerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Fragment/FragmentHandlerTest.php @@ -17,15 +17,15 @@ class FragmentHandlerTest extends \PHPUnit_Framework_TestCase { - private $context; + private $requestStack; public function setUp() { - $this->context = $this->getMockBuilder('Symfony\\Component\\HttpKernel\\RequestContext') + $this->requestStack = $this->getMockBuilder('Symfony\\Component\\HttpFoundation\\RequestStack') ->disableOriginalConstructor() ->getMock() ; - $this->context + $this->requestStack ->expects($this->any()) ->method('getCurrentRequest') ->will($this->returnValue(Request::create('/'))) @@ -37,7 +37,7 @@ public function setUp() */ public function testRenderWhenRendererDoesNotExist() { - $handler = new FragmentHandler(array(), null, $this->context); + $handler = new FragmentHandler(array(), null, $this->requestStack); $handler->render('/', 'foo'); } @@ -87,7 +87,7 @@ protected function getHandler($returnValue, $arguments = array()) call_user_func_array(array($e, 'with'), $arguments); } - $handler = new FragmentHandler(array(), null, $this->context); + $handler = new FragmentHandler(array(), null, $this->requestStack); $handler->addRenderer($renderer); return $handler; diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php index 120e945cd60b1..2f69a94575477 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php @@ -242,7 +242,7 @@ public function testVerifyRequestStackPushPopDuringHandle() { $request = new Request(); - $stack = $this->getMock('Symfony\Component\HttpKernel\RequestStack', array('push', 'pop')); + $stack = $this->getMock('Symfony\Component\HttpFoundation\RequestStack', array('push', 'pop')); $stack->expects($this->at(0))->method('push')->with($this->equalTo($request)); $stack->expects($this->at(1))->method('pop'); diff --git a/src/Symfony/Component/HttpKernel/composer.json b/src/Symfony/Component/HttpKernel/composer.json index 0e8aac54c6af8..a09b0013271c7 100644 --- a/src/Symfony/Component/HttpKernel/composer.json +++ b/src/Symfony/Component/HttpKernel/composer.json @@ -18,7 +18,7 @@ "require": { "php": ">=5.3.3", "symfony/event-dispatcher": "~2.1", - "symfony/http-foundation": "~2.2", + "symfony/http-foundation": "~2.4", "symfony/debug": "~2.3", "psr/log": "~1.0" }, From 1b2ef74a9a0b2f0b866b0faf2543140ed5eac5af Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 8 Sep 2013 15:07:37 +0200 Subject: [PATCH 7/7] [Security] made sure that the exception listener is always removed from the event dispatcher at the end of the request --- .../Component/Security/Http/Firewall.php | 19 ++++++++++++++++++- .../Http/Firewall/ExceptionListener.php | 14 ++++++++++---- src/Symfony/Component/Security/composer.json | 4 ++-- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/Security/Http/Firewall.php b/src/Symfony/Component/Security/Http/Firewall.php index 36df81a80e629..5a1e9d564749f 100644 --- a/src/Symfony/Component/Security/Http/Firewall.php +++ b/src/Symfony/Component/Security/Http/Firewall.php @@ -13,6 +13,7 @@ use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\HttpKernel\Event\FinishRequestEvent; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; @@ -30,6 +31,7 @@ class Firewall implements EventSubscriberInterface { private $map; private $dispatcher; + private $exceptionListeners; /** * Constructor. @@ -41,6 +43,7 @@ public function __construct(FirewallMapInterface $map, EventDispatcherInterface { $this->map = $map; $this->dispatcher = $dispatcher; + $this->exceptionListeners = new \SplObjectStorage(); } /** @@ -57,6 +60,7 @@ public function onKernelRequest(GetResponseEvent $event) // register listeners for this firewall list($listeners, $exception) = $this->map->getListeners($event->getRequest()); if (null !== $exception) { + $this->exceptionListeners[$event->getRequest()] = $exception; $exception->register($this->dispatcher); } @@ -70,8 +74,21 @@ public function onKernelRequest(GetResponseEvent $event) } } + public function onKernelFinishRequest(FinishRequestEvent $event) + { + $request = $event->getRequest(); + + if (isset($this->exceptionListeners[$request])) { + $this->exceptionListeners[$request]->unregister($this->dispatcher); + unset($this->exceptionListeners[$request]); + } + } + public static function getSubscribedEvents() { - return array(KernelEvents::REQUEST => array('onKernelRequest', 8)); + return array( + KernelEvents::REQUEST => array('onKernelRequest', 8), + KernelEvents::FINISH_REQUEST => 'onKernelFinishRequest', + ); } } diff --git a/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php b/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php index abbb4606a6e81..0cca0c46cc394 100644 --- a/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php @@ -69,6 +69,16 @@ public function register(EventDispatcherInterface $dispatcher) $dispatcher->addListener(KernelEvents::EXCEPTION, array($this, 'onKernelException')); } + /** + * Unregisters the dispatcher. + * + * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance + */ + public function unregister(EventDispatcherInterface $dispatcher) + { + $dispatcher->removeListener(KernelEvents::EXCEPTION, array($this, 'onKernelException')); + } + /** * Handles security related exceptions. * @@ -76,10 +86,6 @@ public function register(EventDispatcherInterface $dispatcher) */ public function onKernelException(GetResponseForExceptionEvent $event) { - // we need to remove ourselves as the exception listener can be - // different depending on the Request - $event->getDispatcher()->removeListener(KernelEvents::EXCEPTION, array($this, 'onKernelException')); - $exception = $event->getException(); $request = $event->getRequest(); diff --git a/src/Symfony/Component/Security/composer.json b/src/Symfony/Component/Security/composer.json index b6bbae4515029..fe1299c170e10 100644 --- a/src/Symfony/Component/Security/composer.json +++ b/src/Symfony/Component/Security/composer.json @@ -18,8 +18,8 @@ "require": { "php": ">=5.3.3", "symfony/event-dispatcher": "~2.1", - "symfony/http-foundation": "~2.1", - "symfony/http-kernel": "~2.1" + "symfony/http-foundation": "~2.4", + "symfony/http-kernel": "~2.4" }, "require-dev": { "symfony/form": "~2.0", pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy