Skip to content

Commit 599c865

Browse files
committed
merged branch fabpot/request-stack (PR #8904)
This PR was merged into the master branch. Discussion ---------- Synchronized Service alternative, backwards compatible This is a rebased version #7707. | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #7707 | License | MIT | Doc PR | symfony/symfony-docs#2956 Todo/Questions - [x] do we deprecate the synchronize feature (and removed it in 3.0)? - [x] deal with BC for listeners - [x] rename RequestContext as we already have a class with the same name in the Routing component? - [x] move RequestStack and RequestContext to HttpFoundation? - [x] update documentation Prototype for introducing a ``RequestContext`` in HttpKernel. This PR keeps the synchronized services feature, however introduces a ``RequestContext`` object additionally, that allows to avoid using synchronized service when injecting ``request_context`` instead of ``request`` into a service. The FrameworkBundle is modified such that it does not depend on synchronized services anymore. Users however can still depend on ``request``, activating the synchronized services feature. Features: * Introduced ``REQUEST_FINSHED`` (name is up for grabs) event to handle global state and environment cleanup that should not be done in ``RESPONSE``. Called in both exception or success case correctly * Changed listeners that were synchronized before to using ``onKernelRequestFinished`` and ``RequestContext`` to reset to the parent request (RouterListener + LocaleListener). * Changed ``FragmentHandler`` to use the RequestContext. Added some more tests for this class. * ``RequestStack`` is injected into the ``HttpKernel`` to handle the request finished event and push/pop the stack with requests. Todos: * RequestContext name clashes with Routing components RequestContext. Keep or make unique? * Name for Kernel Request Finished Event could be improved. Commits ------- 1b2ef74 [Security] made sure that the exception listener is always removed from the event dispatcher at the end of the request b1a062d moved RequestStack to HttpFoundation and removed RequestContext 93e60ea [HttpKernel] modified listeners to be BC with Symfony <2.4 018b719 [HttpKernel] tweaked the code f9b10ba [HttpKernel] renamed the kernel finished event a58a8a6 [HttpKernel] changed request_stack to a private service c55f1ea added a RequestStack class
2 parents 08ec911 + 1b2ef74 commit 599c865

File tree

24 files changed

+530
-138
lines changed

24 files changed

+530
-138
lines changed

src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
use Symfony\Bridge\Twig\Extension\HttpKernelExtension;
1515
use Symfony\Bridge\Twig\Tests\TestCase;
1616
use Symfony\Component\HttpFoundation\Request;
17+
use Symfony\Component\HttpFoundation\Response;
18+
use Symfony\Component\HttpFoundation\RequestStack;
1719
use Symfony\Component\HttpKernel\Fragment\FragmentHandler;
1820

1921
class HttpKernelExtensionTest extends TestCase
@@ -23,13 +25,30 @@ class HttpKernelExtensionTest extends TestCase
2325
*/
2426
public function testFragmentWithError()
2527
{
26-
$kernel = $this->getFragmentHandler($this->throwException(new \Exception('foo')));
28+
$renderer = $this->getFragmentHandler($this->throwException(new \Exception('foo')));
2729

28-
$loader = new \Twig_Loader_Array(array('index' => '{{ fragment("foo") }}'));
29-
$twig = new \Twig_Environment($loader, array('debug' => true, 'cache' => false));
30-
$twig->addExtension(new HttpKernelExtension($kernel));
30+
$this->renderTemplate($renderer);
31+
}
32+
33+
public function testRenderFragment()
34+
{
35+
$renderer = $this->getFragmentHandler($this->returnValue(new Response('html')));
36+
37+
$response = $this->renderTemplate($renderer);
3138

32-
$this->renderTemplate($kernel);
39+
$this->assertEquals('html', $response);
40+
}
41+
42+
public function testUnknownFragmentRenderer()
43+
{
44+
$context = $this->getMockBuilder('Symfony\\Component\\HttpFoundation\\RequestStack')
45+
->disableOriginalConstructor()
46+
->getMock()
47+
;
48+
$renderer = new FragmentHandler(array(), false, $context);
49+
50+
$this->setExpectedException('InvalidArgumentException', 'The "inline" renderer does not exist.');
51+
$renderer->render('/foo');
3352
}
3453

3554
protected function getFragmentHandler($return)
@@ -38,8 +57,14 @@ protected function getFragmentHandler($return)
3857
$strategy->expects($this->once())->method('getName')->will($this->returnValue('inline'));
3958
$strategy->expects($this->once())->method('render')->will($return);
4059

41-
$renderer = new FragmentHandler(array($strategy));
42-
$renderer->setRequest(Request::create('/'));
60+
$context = $this->getMockBuilder('Symfony\\Component\\HttpFoundation\\RequestStack')
61+
->disableOriginalConstructor()
62+
->getMock()
63+
;
64+
65+
$context->expects($this->any())->method('getCurrentRequest')->will($this->returnValue(Request::create('/')));
66+
67+
$renderer = new FragmentHandler(array($strategy), false, $context);
4368

4469
return $renderer;
4570
}

src/Symfony/Bundle/FrameworkBundle/Resources/config/fragment_renderer.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<service id="fragment.handler" class="%fragment.handler.class%">
1818
<argument type="collection" />
1919
<argument>%kernel.debug%</argument>
20-
<call method="setRequest"><argument type="service" id="request" on-invalid="null" strict="false" /></call>
20+
<argument type="service" id="request_stack" />
2121
</service>
2222

2323
<service id="fragment.renderer.inline" class="%fragment.renderer.inline.class%">

src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@
9494
<argument type="service" id="router" />
9595
<argument type="service" id="router.request_context" on-invalid="ignore" />
9696
<argument type="service" id="logger" on-invalid="ignore" />
97-
<call method="setRequest"><argument type="service" id="request" on-invalid="null" strict="false" /></call>
97+
<argument type="service" id="request_stack" />
9898
</service>
9999
</services>
100100
</container>

src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
<parameter key="cache_clearer.class">Symfony\Component\HttpKernel\CacheClearer\ChainCacheClearer</parameter>
1313
<parameter key="file_locator.class">Symfony\Component\HttpKernel\Config\FileLocator</parameter>
1414
<parameter key="uri_signer.class">Symfony\Component\HttpKernel\UriSigner</parameter>
15+
<parameter key="request_stack.class">Symfony\Component\HttpFoundation\RequestStack</parameter>
1516
</parameters>
1617

1718
<services>
@@ -23,8 +24,11 @@
2324
<argument type="service" id="event_dispatcher" />
2425
<argument type="service" id="service_container" />
2526
<argument type="service" id="controller_resolver" />
27+
<argument type="service" id="request_stack" />
2628
</service>
2729

30+
<service id="request_stack" class="%request_stack.class%" />
31+
2832
<service id="cache_warmer" class="%cache_warmer.class%">
2933
<argument type="collection" />
3034
</service>

src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
<tag name="kernel.event_subscriber" />
3939
<argument>%kernel.default_locale%</argument>
4040
<argument type="service" id="router" on-invalid="ignore" />
41-
<call method="setRequest"><argument type="service" id="request" on-invalid="null" strict="false" /></call>
41+
<argument type="service" id="request_stack" />
4242
</service>
4343
</services>
4444
</container>

src/Symfony/Component/HttpFoundation/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ CHANGELOG
44
2.4.0
55
-----
66

7+
* added RequestStack
78
* added Request::getEncodings()
89
* added accessors methods to session handlers
910

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\HttpFoundation;
13+
14+
/**
15+
* Request stack that controls the lifecycle of requests.
16+
*
17+
* @author Benjamin Eberlei <kontakt@beberlei.de>
18+
*/
19+
class RequestStack
20+
{
21+
/**
22+
* @var Request[]
23+
*/
24+
private $requests = array();
25+
26+
/**
27+
* Pushes a Request on the stack.
28+
*
29+
* This method should generally not be called directly as the stack
30+
* management should be taken care of by the application itself.
31+
*/
32+
public function push(Request $request)
33+
{
34+
$this->requests[] = $request;
35+
}
36+
37+
/**
38+
* Pops the current request from the stack.
39+
*
40+
* This operation lets the current request go out of scope.
41+
*
42+
* This method should generally not be called directly as the stack
43+
* management should be taken care of by the application itself.
44+
*
45+
* @return Request
46+
*/
47+
public function pop()
48+
{
49+
if (!$this->requests) {
50+
throw new \LogicException('Unable to pop a Request as the stack is already empty.');
51+
}
52+
53+
return array_pop($this->requests);
54+
}
55+
56+
/**
57+
* @return Request|null
58+
*/
59+
public function getCurrentRequest()
60+
{
61+
return end($this->requests) ?: null;
62+
}
63+
64+
/**
65+
* Gets the master Request.
66+
*
67+
* Be warned that making your code aware of the master request
68+
* might make it un-compatible with other features of your framework
69+
* like ESI support.
70+
*
71+
* @return Request|null
72+
*/
73+
public function getMasterRequest()
74+
{
75+
if (!$this->requests) {
76+
return null;
77+
}
78+
79+
return $this->requests[0];
80+
}
81+
82+
/**
83+
* Returns the parent request of the current.
84+
*
85+
* Be warned that making your code aware of the parent request
86+
* might make it un-compatible with other features of your framework
87+
* like ESI support.
88+
*
89+
* If current Request is the master request, it returns null.
90+
*
91+
* @return Request|null
92+
*/
93+
public function getParentRequest()
94+
{
95+
$pos = count($this->requests) - 2;
96+
97+
if (!isset($this->requests[$pos])) {
98+
return null;
99+
}
100+
101+
return $this->requests[$pos];
102+
}
103+
}

src/Symfony/Component/HttpKernel/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
2.4.0
5+
-----
6+
7+
* added the KernelEvents::FINISH_REQUEST event
8+
49
2.3.0
510
-----
611

src/Symfony/Component/HttpKernel/DependencyInjection/ContainerAwareHttpKernel.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\HttpKernel\DependencyInjection;
1313

1414
use Symfony\Component\HttpFoundation\Request;
15+
use Symfony\Component\HttpFoundation\RequestStack;
1516
use Symfony\Component\HttpKernel\HttpKernelInterface;
1617
use Symfony\Component\HttpKernel\HttpKernel;
1718
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
@@ -35,10 +36,11 @@ class ContainerAwareHttpKernel extends HttpKernel
3536
* @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance
3637
* @param ContainerInterface $container A ContainerInterface instance
3738
* @param ControllerResolverInterface $controllerResolver A ControllerResolverInterface instance
39+
* @param RequestStack $requestStack A stack for master/sub requests
3840
*/
39-
public function __construct(EventDispatcherInterface $dispatcher, ContainerInterface $container, ControllerResolverInterface $controllerResolver)
41+
public function __construct(EventDispatcherInterface $dispatcher, ContainerInterface $container, ControllerResolverInterface $controllerResolver, RequestStack $requestStack = null)
4042
{
41-
parent::__construct($dispatcher, $controllerResolver);
43+
parent::__construct($dispatcher, $controllerResolver, $requestStack);
4244

4345
$this->container = $container;
4446

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\HttpKernel\Event;
13+
14+
/**
15+
* Triggered whenever a request is fully processed.
16+
*
17+
* @author Benjamin Eberlei <kontakt@beberlei.de>
18+
*/
19+
class FinishRequestEvent extends KernelEvent
20+
{
21+
}

0 commit comments

Comments
 (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