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 ce22481921f5..9739d96ef385 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 4773339906a4..e613ed11c1d0 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 9e21db451915..34eb33214749 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 674e28f1c98a..607634d1a742 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 177821a5afb2..d2984f5eb460 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 c9b8a211d429..214e3b255dae 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 000000000000..c9d3c39a72cb --- /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 0b864c02f2bc..7b6f2ad208cc 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 777fd11bf40a..f2bad02968e6 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 af9b9ba98b74..099f35a306bf 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 837a16ff370e..71c1b91fc8ac 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 fce48ac3a6ed..e1ad0fa004fe 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 000000000000..f6fdaf3bbe83 --- /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 000000000000..c8de54981d93 --- /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 28901dafdd64..292a5e9f45d1 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 36859baa16b0..2cdfec93de45 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 66fe6bd55d50..2bd1810dca46 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 cec8ae98403a..33e01d54b397 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 1bfa0e5fa822..120e945cd60b 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 607634d1a742..3bcbe16d628c 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 c9d3c39a72cb..ee724843cd84 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 7b6f2ad208cc..2dd16a479c7b 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 f2bad02968e6..a09ec648d1b2 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 71c1b91fc8ac..511d942b654b 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 e1ad0fa004fe..5e6ebcb8d992 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 2cdfec93de45..eb82ebeb1cb6 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 214e3b255dae..c7fea3be7b43 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 2dd16a479c7b..4bfbf9cb5e97 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 a09ec648d1b2..8c94f23a430d 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 099f35a306bf..d54daea9235d 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 511d942b654b..7ac5316adf8f 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 f6fdaf3bbe83..de8aacc3e581 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 c8de54981d93..40e37718b7d1 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 9739d96ef385..445bb036da4a 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 e613ed11c1d0..27fff103fc0f 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 34eb33214749..5db144e814fe 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 d2984f5eb460..3f6e455aab66 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 4bfbf9cb5e97..2170376b9804 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 8c94f23a430d..5ed590d4570b 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 d54daea9235d..d7cc5d182791 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 eb82ebeb1cb6..270a11d29518 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 2bd1810dca46..07be703f87ff 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 33e01d54b397..1ea7b50c3374 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 445bb036da4a..8ce564265ec9 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 27fff103fc0f..a1beee30a1fb 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 5db144e814fe..6b2f7c968869 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 3bcbe16d628c..608bf42d5253 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 3f6e455aab66..6c1dd73e2e61 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 954b66ac43c0..061d47e7eec9 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 40e37718b7d1..71bfd106991f 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 c06dd3fa57e0..b36e9358ff13 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 c7fea3be7b43..69e7937d18c1 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 2170376b9804..7cab6aa39b56 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 5ed590d4570b..d122388b4b08 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 d7cc5d182791..05b6a086e970 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 7ac5316adf8f..0be8e1b4dbb7 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 de8aacc3e581..000000000000 --- 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 292a5e9f45d1..2c8a6a28ec14 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 270a11d29518..d128753ffab0 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 07be703f87ff..ac742b35e08c 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 1ea7b50c3374..dbf6b20b424e 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 120e945cd60b..2f69a9457547 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 0e8aac54c6af..a09b0013271c 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 36df81a80e62..5a1e9d564749 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 abbb4606a6e8..0cca0c46cc39 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 b6bbae451502..fe1299c170e1 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