Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

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

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
GH-7007: Synchronized Service alternative, backwards compatible.
  • Loading branch information
beberlei committed Apr 30, 2013
commit db4d9348c07e006617f92ede98ea749e47c8d996
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,9 @@
<tag name="kernel.event_subscriber" />
<tag name="monolog.logger" channel="request" />
<argument type="service" id="router" />
<argument type="service" id="request_context" />
<argument type="service" id="router.request_context" on-invalid="ignore" />
<argument type="service" id="logger" on-invalid="ignore" />
<call method="setRequest"><argument type="service" id="request" on-invalid="null" strict="false" /></call>
</service>
</services>
</container>
10 changes: 10 additions & 0 deletions 10 src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
<parameter key="cache_clearer.class">Symfony\Component\HttpKernel\CacheClearer\ChainCacheClearer</parameter>
<parameter key="file_locator.class">Symfony\Component\HttpKernel\Config\FileLocator</parameter>
<parameter key="uri_signer.class">Symfony\Component\HttpKernel\UriSigner</parameter>
<parameter key="request_stack.class">Symfony\Component\HttpKernel\RequestStack</parameter>
<parameter key="request_context.class">Symfony\Component\HttpKernel\RequestContext</parameter>
</parameters>

<services>
Expand All @@ -23,6 +25,14 @@
<argument type="service" id="event_dispatcher" />
<argument type="service" id="service_container" />
<argument type="service" id="controller_resolver" />
<argument type="service" id="request_stack" />
</service>

<service id="request_stack" class="%request_stack.class%">
Copy link
Member

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?

</service>

<service id="request_context" class="%request_context.class%">
<argument type="service" id="request_stack" />
</service>

<service id="cache_warmer" class="%cache_warmer.class%">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@
<service id="locale_listener" class="%locale_listener.class%">
<tag name="kernel.event_subscriber" />
<argument>%kernel.default_locale%</argument>
<argument type="service" id="request_context" />
<argument type="service" id="router" on-invalid="ignore" />
<call method="setRequest"><argument type="service" id="request" on-invalid="null" strict="false" /></call>
</service>
</services>
</container>
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)
Copy link
Member

Choose a reason for hiding this comment

The 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'));
}

Expand All @@ -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');
Expand All @@ -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;
}
}
48 changes: 37 additions & 11 deletions 48 src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)
Copy link
Member

Choose a reason for hiding this comment

The 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)),
Copy link
Member

Choose a reason for hiding this comment

The 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).

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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
Expand Up @@ -13,9 +13,11 @@

use Psr\Log\LoggerInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
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;
Expand All @@ -35,6 +37,7 @@ class RouterListener implements EventSubscriberInterface
private $matcher;
private $context;
private $logger;
private $kernelContext;

/**
* Constructor.
Expand All @@ -45,7 +48,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.');
Expand All @@ -57,6 +60,7 @@ public function __construct($matcher, RequestContext $context = null, LoggerInte

$this->matcher = $matcher;
$this->context = $context ?: $matcher->getContext();
$this->kernelContext = $kernelContext;
$this->logger = $logger;
}

Expand All @@ -77,6 +81,11 @@ public function setRequest(Request $request = null)
}
}

public function onKernelResponse(FilterResponseEvent $event)
{
$this->setRequest($this->kernelContext->getParentRequest());
}

public function onKernelRequest(GetResponseEvent $event)
{
$request = $event->getRequest();
Expand Down Expand Up @@ -133,6 +142,7 @@ public static function getSubscribedEvents()
{
return array(
KernelEvents::REQUEST => array(array('onKernelRequest', 32)),
KernelEvents::RESPONSE => array(array('onKernelResponse', -255)),
);
}
}
44 changes: 44 additions & 0 deletions 44 src/Symfony/Component/HttpKernel/RequestContext.php
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

accidently

Copy link
Contributor

Choose a reason for hiding this comment

The 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();
}
}
69 changes: 69 additions & 0 deletions 69 src/Symfony/Component/HttpKernel/RequestStack.php
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];
}
}
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.