-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
GH-7007: Synchronized Service alternative, backwards compatible. #7707
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
db4d934
705f0d4
01ac8c9
ec539ae
0ef3664
778eaea
5d06aff
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,7 @@ | |
use Symfony\Component\HttpFoundation\Response; | ||
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,19 +30,23 @@ | |
class ContainerAwareHttpKernel extends HttpKernel | ||
{ | ||
protected $container; | ||
protected $requestStack; | ||
|
||
/** | ||
* Constructor. | ||
* | ||
* @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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should accept null by default for BC. |
||
{ | ||
parent::__construct($dispatcher, $controllerResolver); | ||
|
||
$this->requestStack = $requestStack; | ||
$this->container = $container; | ||
|
||
$container->addScope(new Scope('request')); | ||
} | ||
|
||
|
@@ -50,6 +55,8 @@ public function __construct(EventDispatcherInterface $dispatcher, ContainerInter | |
*/ | ||
public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true) | ||
{ | ||
$this->requestStack->push($request); | ||
|
||
$request->headers->set('X-Php-Ob-Level', ob_get_level()); | ||
|
||
$this->container->enterScope('request'); | ||
|
@@ -67,6 +74,8 @@ public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQ | |
$this->container->set('request', null, 'request'); | ||
$this->container->leaveScope('request'); | ||
|
||
$this->requestStack->pop(); | ||
|
||
return $response; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,7 +12,9 @@ | |
namespace Symfony\Component\HttpKernel\EventListener; | ||
|
||
use Symfony\Component\HttpKernel\Event\GetResponseEvent; | ||
use Symfony\Component\HttpKernel\Event\FilterResponseEvent; | ||
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,65 @@ 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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's a BC break. Not sure how to deal with it. The only thing that comes to my mind is to not used the new request context and keep the old way. |
||
{ | ||
$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 onKernelResponse(FilterResponseEvent $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)), | ||
// should be registered very late | ||
KernelEvents::RESPONSE => array(array('onKernelResponse', -255)), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are reintroducing the exact same bug as we had before synchronized services. Using the response event is not an option here as it is not always called (think of a sub-request that throws an exception for instance). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry my ignorance, It slipped me that it worked this way before. I thought this was viable to get rid of the explicit event for leaving the scope and remove the dependency on EventDispatcher in the RequestStack, but I guess I have to reintroduce this then. I will rethink my approach. |
||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
<?php | ||
|
||
namespace Symfony\Component\HttpKernel; | ||
|
||
/** | ||
* Registry for Requests. | ||
* | ||
* Facade for RequestStack that prevents modification of the stack, | ||
* so that users don't accidentily push()/pop() from the stack and | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. accidently There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. accidentally |
||
* mess up the request cycle. | ||
*/ | ||
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(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
<?php | ||
|
||
namespace Symfony\Component\HttpKernel; | ||
|
||
use Symfony\Component\HttpFoundation\Request; | ||
|
||
/** | ||
* Request stack that controls the lifecycle of requests. | ||
* | ||
* Notifies services of changes in the stack. | ||
*/ | ||
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 | ||
*/ | ||
public function getCurrentRequest() | ||
{ | ||
return end($this->requests); | ||
} | ||
|
||
/** | ||
* @return Request | ||
*/ | ||
public function getMasterRequest() | ||
{ | ||
return $this->requests[0]; | ||
} | ||
|
||
/** | ||
* Return the parent request of the current. | ||
* | ||
* If current Request ist 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]; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about marking it private?