Skip to content

Instantly share code, notes, and snippets.

@beberlei
Last active December 16, 2015 03:30
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save beberlei/d14fd7f2e734df56fe61 to your computer and use it in GitHub Desktop.
Save beberlei/d14fd7f2e734df56fe61 to your computer and use it in GitHub Desktop.
Symfony RequestStack and RequestRegistry
<?php
namespace Symfony\Component\HttpFoundation;
/**
* Registry for Requests.
*
* Facade for RequestStack that prevents modification of the stack,
* so that users don't accidentily push()/pop() from the stack and
* mess up the request cycle.
*/
class RequestRegistry
{
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();
}
}
<?php
namespace Symfony\Component\HttpFoundation;
/**
* Request stack that controls the lifecycle of requests.
*
* Notifies services of changes in the stack.
*/
class RequestStack
{
/**
* @var Request
*/
private $masterRequest;
/**
* @var Request[]
*/
private $requests = array();
private $eventDispatcher;
public function __construct(EventDispatcherInterface $eventDispatcher)
{
$this->eventDispatcher = $eventDispatcher;
}
public function push(Request $request)
{
if (HttpKernelInterface::MASTER_REQUEST === $request->getType()) {
$this->masterRequest = $request;
}
$this->requests[] = $request;
$this->dispatch('request.enter_scope', new RequestEnterScopeEvent($request));
}
/**
* Pop the current request from the stack.
*
* This operation lets the current request go out of scope.
*
* @return Request
*/
public function pop()
{
$previousRequest = array_pop($this->requests);
$this->dispatch('request.leave_scope',
new RequestLeaveScopeEvent(
$previousRequest,
$this->getCurrentRequest()
)
);
return $request;
}
/**
* @return Request
*/
public function getCurrentRequest()
{
return end($this->requests);
}
/**
* @return Request
*/
public function getMasterRequest()
{
return $this->masterRequest;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\DependencyInjection;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\HttpKernel;
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Scope;
/**
* Adds a managed request scope.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class RequestStackAwareHttpKernel extends HttpKernel
{
protected $stack;
/**
* Constructor.
*
* @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance
* @param ControllerResolverInterface $controllerResolver A ControllerResolverInterface instance
*/
public function __construct(EventDispatcherInterface $dispatcher, ControllerResolverInterface $controllerResolver, RequestStack $stack)
{
parent::__construct($dispatcher, $controllerResolver);
$this->stack = $stack;
}
/**
* {@inheritdoc}
*/
public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
{
$request->headers->set('X-Php-Ob-Level', ob_get_level());
$this->stack->push($request);
try {
$response = parent::handle($request, $type, $catch);
} catch (\Exception $e) {
$this->stack->pop();
throw $e;
}
$this->stack->pop();
return $response;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\EventListener;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\RequestContextAwareInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Initializes the locale based on the current request.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class LocaleListener implements EventSubscriberInterface
{
private $router;
private $defaultLocale;
public function __construct($defaultLocale = 'en', RequestContextAwareInterface $router = null)
{
$this->defaultLocale = $defaultLocale;
$this->router = $router;
}
public function onRequestLeaveScope(RequestLeaveScopeEvent $event)
{
$request = $event->getCurrentRequest();
if (null === $request) {
return;
}
if ($locale = $request->attributes->get('_locale')) {
$request->setLocale($locale);
}
if (null !== $this->router) {
$this->router->getContext()->setParameter('_locale', $request->getLocale());
}
}
public function onRequestEnterScope(RequestEnterScopeEvent $event)
{
$request = $event->getRequest();
$request->setDefaultLocale($this->defaultLocale);
$this->setRequest($request);
}
public static function getSubscribedEvents()
{
return array(
// TODO Adjust
);
}
}
Copy link

ghost commented Apr 12, 2013

@Baachi Why extend SplStack? it has a HUGE api where here we only need push()/pop(). This would create a big unnecessary API

@beberlei I agree with you

@beberlei
Copy link
Author

Please review symfony/symfony#7707 which is the pull request for this idea.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment