*
* @see FragmentRendererInterface
@@ -31,15 +37,19 @@ class FragmentHandler
private $debug;
private $renderers;
private $request;
+ private $requestStack;
/**
* Constructor.
*
+ * 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)
+ public function __construct(array $renderers = array(), $debug = false, RequestStack $requestStack = null)
{
+ $this->requestStack = $requestStack;
$this->renderers = array();
foreach ($renderers as $renderer) {
$this->addRenderer($renderer);
@@ -60,7 +70,13 @@ public function addRenderer(FragmentRendererInterface $renderer)
/**
* Sets the current Request.
*
- * @param Request $request 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)
{
@@ -93,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->request) {
- throw new \LogicException('Rendering a fragment can only be done when handling a master Request.');
+ 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->request, $options));
+ return $this->deliver($this->renderers[$renderer]->render($uri, $request, $options));
}
/**
@@ -115,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->request->getUri(), $response->getStatusCode()));
+ throw new \RuntimeException(sprintf('Error when rendering "%s" (Status code is %s).', $this->getRequest()->getUri(), $response->getStatusCode()));
}
if (!$response instanceof StreamedResponse) {
@@ -124,4 +140,9 @@ protected function deliver(Response $response)
$response->sendContent();
}
+
+ private function getRequest()
+ {
+ 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 837a16ff370e..0be8e1b4dbb7 100644
--- a/src/Symfony/Component/HttpKernel/HttpKernel.php
+++ b/src/Symfony/Component/HttpKernel/HttpKernel.php
@@ -16,11 +16,13 @@
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
+use Symfony\Component\HttpKernel\Event\FinishRequestEvent;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
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;
@@ -35,19 +37,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();
}
/**
@@ -61,6 +66,8 @@ public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQ
return $this->handleRaw($request, $type);
} catch (\Exception $e) {
if (false === $catch) {
+ $this->finishRequest($request, $type);
+
throw $e;
}
@@ -93,6 +100,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 +165,27 @@ private function filterResponse(Response $response, Request $request, $type)
$this->dispatcher->dispatch(KernelEvents::RESPONSE, $event);
+ $this->finishRequest($request, $type);
+
return $event->getResponse();
}
+ /**
+ * Publishes the finish request event, then pop the request from the stack.
+ *
+ * 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
+ */
+ private function finishRequest(Request $request, $type)
+ {
+ $this->dispatcher->dispatch(KernelEvents::FINISH_REQUEST, new FinishRequestEvent($this, $request, $type));
+ $this->requestStack->pop();
+ }
+
/**
* Handles an exception by trying to convert it to a Response.
*
@@ -179,6 +206,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/KernelEvents.php b/src/Symfony/Component/HttpKernel/KernelEvents.php
index fce48ac3a6ed..5e6ebcb8d992 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 FINISH_REQUEST = 'kernel.finish_request';
}
diff --git a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/ContainerAwareHttpKernelTest.php b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/ContainerAwareHttpKernelTest.php
index 28901dafdd64..2c8a6a28ec14 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\HttpFoundation\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\HttpFoundation\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..d128753ffab0 100644
--- a/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php
@@ -11,16 +11,24 @@
namespace Symfony\Component\HttpKernel\Tests\EventListener;
-use Symfony\Component\HttpKernel\EventListener\LocaleListener;
+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 $requestStack;
+
+ protected function setUp()
+ {
+ $this->requestStack = $this->getMock('Symfony\Component\HttpFoundation\RequestStack', array(), array(), '', false);
+ }
+
public function testDefaultLocaleWithoutSession()
{
- $listener = new LocaleListener('fr');
+ $listener = new LocaleListener('fr', null, $this->requestStack);
$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', null, $this->requestStack);
$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', $router, $this->requestStack);
$listener->onKernelRequest($this->getEvent($request));
}
+ public function testRouterResetWithParentRequestOnKernelFinishRequest()
+ {
+ 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->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->requestStack);
+ $listener->onKernelFinishRequest($event);
+ }
+
public function testRequestLocaleIsNotOverridden()
{
$request = Request::create('/');
$request->setLocale('de');
- $listener = new LocaleListener('fr');
+ $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 66fe6bd55d50..ac742b35e08c 100644
--- a/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterListenerTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterListenerTest.php
@@ -11,14 +11,22 @@
namespace Symfony\Component\HttpKernel\Tests\EventListener;
-use Symfony\Component\HttpKernel\EventListener\RouterListener;
+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 $requestStack;
+
+ public function setUp()
+ {
+ $this->requestStack = $this->getMock('Symfony\Component\HttpFoundation\RequestStack', 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, null, null, $this->requestStack);
$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(), null, null, $this->requestStack);
}
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, new RequestContext(), null, $this->requestStack);
$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, 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 cec8ae98403a..dbf6b20b424e 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 $requestStack;
+
+ public function setUp()
+ {
+ $this->requestStack = $this->getMockBuilder('Symfony\\Component\\HttpFoundation\\RequestStack')
+ ->disableOriginalConstructor()
+ ->getMock()
+ ;
+ $this->requestStack
+ ->expects($this->any())
+ ->method('getCurrentRequest')
+ ->will($this->returnValue(Request::create('/')))
+ ;
+ }
+
/**
* @expectedException \InvalidArgumentException
*/
public function testRenderWhenRendererDoesNotExist()
{
- $handler = new FragmentHandler();
+ $handler = new FragmentHandler(array(), null, $this->requestStack);
$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(array(), null, $this->requestStack);
$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..2f69a9457547 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\HttpFoundation\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) {
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"
},
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