Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 877603a

Browse files
committed
merged branch fabpot/content-renderer-request (PR #6829)
This PR was merged into the master branch. Commits ------- 23f5145 renamed proxy to router_proxy e5135f6 [HttpKernel] renamed path to _path to avoid collision 3193a90 made the proxy path configurable ad82893 removed the need for a proxy route for rendering strategies b9f0e17 [HttpKernel] made the Request required when using rendering strategies Discussion ---------- Content renderer simplification | Q | A | ------------- | --- | Bug fix? | no | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | n/a | License | MIT | Doc PR | symfony/symfony-docs#2179 Todo: - [x] submit a PR for documentation update The first commit makes the Request required when dealing with rendering strategies (see the commit why this was a bad idea to make it optional in the first place). The second commit removes the need for a proxy route and replaces it with the same system we have in the security component. The third commit makes the proxy path configurable (default to `/_proxy`). This PR has been triggered by a discussion on #6791. --------------------------------------------------------------------------- by fabpot at 2013-01-22T09:49:37Z My opinion: * The first commit should be merged. * For the second and third one, I don't have a strong opinion. One of the benefits that the content renderer and its strategies do not rely on the Routing component anymore. --------------------------------------------------------------------------- by fabpot at 2013-01-22T15:22:47Z Any comments? ping @Tobion @vicb --------------------------------------------------------------------------- by Tobion at 2013-01-22T16:07:15Z Shouldn't the class name be like `SubRequestRenderingStrategyInterface` because currently it does not say anything about what is rendered. `RenderingStrategyInterface` makes it look like it's for rendering a normal master request, i.e. templating. --------------------------------------------------------------------------- by fabpot at 2013-01-22T16:19:26Z @Tobion: This was actually the first name I had but I found it too long. It is indeed rendering a normal request, but only in the context of a master request. --------------------------------------------------------------------------- by Tobion at 2013-01-22T16:23:25Z I found the correct term for what this is about: http://en.wikipedia.org/wiki/Transclusion So it should probably be like `Symfony/Component/HttpKernel/Transclusion/TransclusionInterface` or `TransclusionStrategyInterface`. So the term `rendering` is misleading as it does not really render the subrequest, but only prints a reference to the subrequest. The rendering is done by ESI processor or hinclude etc. --------------------------------------------------------------------------- by fabpot at 2013-01-22T16:37:00Z The `RenderingStrategyInterface` does render a request and returns a Response. One of the strategy consist of returning an ESI tag, but this is still a Response. I don't like introducing the `Transclusion` word as (at least for me) it does not evoke anything. --------------------------------------------------------------------------- by Tobion at 2013-01-22T16:46:10Z Also `DefaultRenderingStrategy` is not saying anything. What is default? It should express that it directly includes the resource in the other (term `integrate` comes to my mind). --------------------------------------------------------------------------- by kriswallsmith at 2013-01-22T17:23:21Z How about `InlineRenderingStrategy`? --------------------------------------------------------------------------- by vicb at 2013-01-22T17:25:17Z @Tobion @kriswallsmith 👍 --------------------------------------------------------------------------- by kriswallsmith at 2013-01-22T17:26:17Z Also, `SubRequestStrategyInterface` may be more apparent (`InlineSubRequestStrategy`, `EsiSubRequestStrategy`…) --------------------------------------------------------------------------- by Tobion at 2013-01-22T18:10:19Z `SubRequestStrategyInterface` is missing the verb somehow. A strategy for what? @kriswallsmith as an English native speaker, is transclusion also not convenient for you? --------------------------------------------------------------------------- by fabpot at 2013-01-22T18:11:41Z Thanks for all your suggestions, I appreciate them, but what about the whole approach? Do you agree that it is better than the current one? I'd like to avoid the bikeshedding if the approach is not better. --------------------------------------------------------------------------- by kriswallsmith at 2013-01-22T18:22:47Z :+1: for removing the router dependency. @Tobion perhaps request is the verb there? --------------------------------------------------------------------------- by Tobion at 2013-01-22T19:51:20Z I'm also fine with making it independent from the routing component because routing is about making routes configurable with placeholders etc. for nice URLs. But this is not needed for a proxy feature. --------------------------------------------------------------------------- by kriswallsmith at 2013-01-22T20:13:48Z @fabpot Do you anticipate ever wanting a sub request to be handled differently based on HTTP method? Just thinking of possible reasons to continue using the routing component here… --------------------------------------------------------------------------- by fabpot at 2013-01-22T20:40:06Z No, sub-requests only make sense for GET requests. In fact, we even enforce that in HttpContentRenderer. --------------------------------------------------------------------------- by fabpot at 2013-01-23T06:51:54Z I'm not going to discuss names further in the context of this PR as it has already been discussed in the initial PR that introduced these classes and because this PR does not change anything to the meaning of these classes. If you think the names can be better, feel free to open a ticket and discuss names there. --------------------------------------------------------------------------- by vicb at 2013-01-23T07:48:36Z If I understand correctly, both hsi and esi will generate path starting with "/_proxy", isn't it a problem wrt access_control ? should it be possible to configure a per strategy path ? --------------------------------------------------------------------------- by fabpot at 2013-01-23T07:56:11Z @vicb: Yes, all strategies use the `/_proxy` path when the developer uses a controller reference. But the router proxy takes care of securing the route, so there is no need to do it yourself. --------------------------------------------------------------------------- by vicb at 2013-01-23T08:07:36Z @fabpot that's smart, I've missed it. Some questions though (they should be answered by UT I think - and might already have been, I have not checked) - Isn't there a pb with urlencoding in the listener ? - Would the listener work with fragments (`#...') ? --------------------------------------------------------------------------- by vicb at 2013-01-23T08:31:37Z Some more points: - Should we validate that the router_proxy is enabled when esi are enabled (early failure ?) - Should we be able to enable each strategy individually (ie no need to expose the signer when hsi are not used) --------------------------------------------------------------------------- by fabpot at 2013-01-23T09:58:45Z Enabling the router proxy when using ESI si not required. The router proxy is "only" required when you use the `controller` Twig function (or the equivalent in PHP -> `ControllerReference`). But we can probably throw an exception in the `ControllerReference` constructor if the proxy is not enabled. Enabling each strategy individually is indeed a good idea (and that's more a general question as we could do the same for the translator loaders, or the service container loaders). Let's create another issue on this global topic. --------------------------------------------------------------------------- by vicb at 2013-01-23T10:10:29Z > But we can probably throw an exception in the ControllerReference constructor if the proxy is not enabled. It should probably be in a wrapper class then ? --------------------------------------------------------------------------- by fabpot at 2013-01-23T12:45:36Z The listener does not need to work with fragments as URLs as they are never part of the generated URL.
2 parents 8a351f0 + 23f5145 commit 877603a

24 files changed

+275
-329
lines changed

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

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Symfony\Bridge\Twig\Extension\HttpKernelExtension;
1515
use Symfony\Bridge\Twig\Tests\TestCase;
16+
use Symfony\Component\HttpFoundation\Request;
1617
use Symfony\Component\HttpFoundation\Response;
1718
use Symfony\Component\HttpKernel\HttpContentRenderer;
1819

@@ -29,13 +30,6 @@ protected function setUp()
2930
}
3031
}
3132

32-
public function testRenderWithoutMasterRequest()
33-
{
34-
$kernel = $this->getHttpContentRenderer($this->returnValue(new Response('foo')));
35-
36-
$this->assertEquals('foo', $this->renderTemplate($kernel));
37-
}
38-
3933
/**
4034
* @expectedException \Twig_Error_Runtime
4135
*/
@@ -56,7 +50,18 @@ protected function getHttpContentRenderer($return)
5650
$strategy->expects($this->once())->method('getName')->will($this->returnValue('default'));
5751
$strategy->expects($this->once())->method('render')->will($return);
5852

59-
return new HttpContentRenderer(array($strategy));
53+
// simulate a master request
54+
$event = $this->getMockBuilder('Symfony\Component\HttpKernel\Event\GetResponseEvent')->disableOriginalConstructor()->getMock();
55+
$event
56+
->expects($this->once())
57+
->method('getRequest')
58+
->will($this->returnValue(Request::create('/')))
59+
;
60+
61+
$renderer = new HttpContentRenderer(array($strategy));
62+
$renderer->onKernelRequest($event);
63+
64+
return $renderer;
6065
}
6166

6267
protected function renderTemplate(HttpContentRenderer $renderer, $template = '{{ render("foo") }}')

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ public function getConfigTreeBuilder()
7373

7474
$this->addFormSection($rootNode);
7575
$this->addEsiSection($rootNode);
76+
$this->addRouterProxySection($rootNode);
7677
$this->addProfilerSection($rootNode);
7778
$this->addRouterSection($rootNode);
7879
$this->addSessionSection($rootNode);
@@ -114,6 +115,21 @@ private function addEsiSection(ArrayNodeDefinition $rootNode)
114115
;
115116
}
116117

118+
private function addRouterProxySection(ArrayNodeDefinition $rootNode)
119+
{
120+
$rootNode
121+
->children()
122+
->arrayNode('router_proxy')
123+
->info('proxy configuration for the HTTP content renderer')
124+
->canBeDisabled()
125+
->children()
126+
->scalarNode('path')->defaultValue('/_proxy')->end()
127+
->end()
128+
->end()
129+
->end()
130+
;
131+
}
132+
117133
private function addProfilerSection(ArrayNodeDefinition $rootNode)
118134
{
119135
$rootNode

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ public function load(array $configs, ContainerBuilder $container)
9494
$this->registerEsiConfiguration($config['esi'], $loader);
9595
}
9696

97+
if (isset($config['router_proxy'])) {
98+
$this->registerRouterProxyConfiguration($config['router_proxy'], $container, $loader);
99+
}
100+
97101
if (isset($config['profiler'])) {
98102
$this->registerProfilerConfiguration($config['profiler'], $container, $loader);
99103
}
@@ -184,6 +188,20 @@ private function registerEsiConfiguration(array $config, XmlFileLoader $loader)
184188
}
185189
}
186190

191+
/**
192+
* Loads the router proxy configuration.
193+
*
194+
* @param array $config A proxy configuration array
195+
* @param XmlFileLoader $loader An XmlFileLoader instance
196+
*/
197+
private function registerRouterProxyConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader)
198+
{
199+
if (!empty($config['enabled'])) {
200+
$loader->load('proxy.xml');
201+
$container->setParameter('http_content_renderer.proxy_path', $config['path']);
202+
}
203+
}
204+
187205
/**
188206
* Loads the profiler configuration.
189207
*

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

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<parameter key="http_content_renderer.strategy.default.class">Symfony\Component\HttpKernel\RenderingStrategy\DefaultRenderingStrategy</parameter>
1010
<parameter key="http_content_renderer.strategy.hinclude.class">Symfony\Component\HttpKernel\RenderingStrategy\HIncludeRenderingStrategy</parameter>
1111
<parameter key="http_content_renderer.strategy.hinclude.global_template"></parameter>
12-
<parameter key="http_content_renderer.listener.router_proxy.class">Symfony\Component\HttpKernel\EventListener\RouterProxyListener</parameter>
12+
<parameter key="http_content_renderer.proxy_path">/_proxy</parameter>
1313
</parameters>
1414

1515
<services>
@@ -22,21 +22,15 @@
2222
<service id="http_content_renderer.strategy.default" class="%http_content_renderer.strategy.default.class%">
2323
<tag name="kernel.content_renderer_strategy" />
2424
<argument type="service" id="http_kernel" />
25-
<call method="setUrlGenerator"><argument type="service" id="router" /></call>
25+
<call method="setProxyPath"><argument>%http_content_renderer.proxy_path%</argument></call>
2626
</service>
2727

2828
<service id="http_content_renderer.strategy.hinclude" class="%http_content_renderer.strategy.hinclude.class%">
2929
<tag name="kernel.content_renderer_strategy" />
3030
<argument type="service" id="templating" on-invalid="null" />
3131
<argument type="service" id="uri_signer" />
3232
<argument>%http_content_renderer.strategy.hinclude.global_template%</argument>
33-
<call method="setUrlGenerator"><argument type="service" id="router" /></call>
34-
</service>
35-
36-
<!-- FIXME: make the listener registration optional via a configuration setting? -->
37-
<service id="http_content_renderer.listener.router_proxy" class="%http_content_renderer.listener.router_proxy.class%">
38-
<tag name="kernel.event_subscriber" />
39-
<argument type="service" id="uri_signer" />
33+
<call method="setProxyPath"><argument>%http_content_renderer.proxy_path%</argument></call>
4034
</service>
4135

4236
</services>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
<tag name="kernel.content_renderer_strategy" />
2323
<argument type="service" id="esi" />
2424
<argument type="service" id="http_content_renderer.strategy.default" />
25-
<call method="setUrlGenerator"><argument type="service" id="router" /></call>
25+
<call method="setProxyPath"><argument>%http_content_renderer.proxy_path%</argument></call>
2626
</service>
2727
</services>
2828
</container>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?xml version="1.0" ?>
2+
3+
<container xmlns="http://symfony.com/schema/dic/services"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
6+
7+
<parameters>
8+
<parameter key="http_content_renderer.listener.router_proxy.class">Symfony\Component\HttpKernel\EventListener\RouterProxyListener</parameter>
9+
</parameters>
10+
11+
<services>
12+
<service id="http_content_renderer.listener.router_proxy" class="%http_content_renderer.listener.router_proxy.class%">
13+
<tag name="kernel.event_subscriber" />
14+
<argument type="service" id="uri_signer" />
15+
<argument>%http_content_renderer.proxy_path%</argument>
16+
</service>
17+
</services>
18+
</container>

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

Lines changed: 0 additions & 10 deletions
This file was deleted.

src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
<xsd:element name="form" type="form" minOccurs="0" maxOccurs="1" />
1313
<xsd:element name="csrf-protection" type="csrf_protection" minOccurs="0" maxOccurs="1" />
1414
<xsd:element name="esi" type="esi" minOccurs="0" maxOccurs="1" />
15+
<xsd:element name="router-proxy" type="router-proxy" minOccurs="0" maxOccurs="1" />
1516
<xsd:element name="profiler" type="profiler" minOccurs="0" maxOccurs="1" />
1617
<xsd:element name="router" type="router" minOccurs="0" maxOccurs="1" />
1718
<xsd:element name="session" type="session" minOccurs="0" maxOccurs="1" />
@@ -44,6 +45,11 @@
4445
<xsd:attribute name="enabled" type="xsd:boolean" />
4546
</xsd:complexType>
4647

48+
<xsd:complexType name="router-proxy">
49+
<xsd:attribute name="enabled" type="xsd:boolean" />
50+
<xsd:attribute name="path" type="xsd:string" />
51+
</xsd:complexType>
52+
4753
<xsd:complexType name="profiler">
4854
<xsd:all>
4955
<xsd:element name="matcher" type="profiler_matcher" minOccurs="0" maxOccurs="1" />

src/Symfony/Component/HttpKernel/EventListener/RouterProxyListener.php

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,18 @@
3030
class RouterProxyListener implements EventSubscriberInterface
3131
{
3232
private $signer;
33+
private $proxyPath;
3334

34-
public function __construct(UriSigner $signer)
35+
/**
36+
* Constructor.
37+
*
38+
* @param UriSigner $signer A UriSigner instance
39+
* @param string $proxyPath The path that triggers this listener
40+
*/
41+
public function __construct(UriSigner $signer, $proxyPath = '/_proxy')
3542
{
3643
$this->signer = $signer;
44+
$this->proxyPath = $proxyPath;
3745
}
3846

3947
/**
@@ -47,16 +55,16 @@ public function onKernelRequest(GetResponseEvent $event)
4755
{
4856
$request = $event->getRequest();
4957

50-
if ('_proxy' !== $request->attributes->get('_route')) {
58+
if ($this->proxyPath !== rawurldecode($request->getPathInfo())) {
5159
return;
5260
}
5361

5462
$this->validateRequest($request);
5563

56-
parse_str($request->query->get('path', ''), $attributes);
64+
parse_str($request->query->get('_path', ''), $attributes);
5765
$request->attributes->add($attributes);
5866
$request->attributes->set('_route_params', array_replace($request->attributes->get('_route_params', array()), $attributes));
59-
$request->query->remove('path');
67+
$request->query->remove('_path');
6068
}
6169

6270
protected function validateRequest(Request $request)
@@ -92,7 +100,7 @@ protected function getLocalIpAddresses()
92100
public static function getSubscribedEvents()
93101
{
94102
return array(
95-
KernelEvents::REQUEST => array(array('onKernelRequest', 16)),
103+
KernelEvents::REQUEST => array(array('onKernelRequest', 48)),
96104
);
97105
}
98106
}

src/Symfony/Component/HttpKernel/HttpContentRenderer.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,13 @@
2323
/**
2424
* Renders a URI using different strategies.
2525
*
26+
* This class handles sub-requests. The response content from the sub-request
27+
* is then embedded into a master request. The handling of the sub-request
28+
* is managed by rendering strategies.
29+
*
2630
* @author Fabien Potencier <[email protected]>
31+
*
32+
* @see RenderingStrategyInterface
2733
*/
2834
class HttpContentRenderer implements EventSubscriberInterface
2935
{
@@ -103,9 +109,7 @@ public function render($uri, $strategy = 'default', array $options = array())
103109
throw new \InvalidArgumentException(sprintf('The "%s" rendering strategy does not exist.', $strategy));
104110
}
105111

106-
$request = $this->requests ? $this->requests[0] : null;
107-
108-
return $this->deliver($this->strategies[$strategy]->render($uri, $request, $options));
112+
return $this->deliver($this->strategies[$strategy]->render($uri, $this->requests[0], $options));
109113
}
110114

111115
/**

src/Symfony/Component/HttpKernel/RenderingStrategy/DefaultRenderingStrategy.php

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
*
2222
* @author Fabien Potencier <[email protected]>
2323
*/
24-
class DefaultRenderingStrategy extends GeneratorAwareRenderingStrategy
24+
class DefaultRenderingStrategy extends ProxyAwareRenderingStrategy
2525
{
2626
private $kernel;
2727

@@ -42,7 +42,7 @@ public function __construct(HttpKernelInterface $kernel)
4242
*
4343
* * alt: an alternative URI to render in case of an error
4444
*/
45-
public function render($uri, Request $request = null, array $options = array())
45+
public function render($uri, Request $request, array $options = array())
4646
{
4747
if ($uri instanceof ControllerReference) {
4848
$uri = $this->generateProxyUri($uri, $request);
@@ -74,21 +74,16 @@ public function render($uri, Request $request = null, array $options = array())
7474
}
7575
}
7676

77-
protected function createSubRequest($uri, Request $request = null)
77+
protected function createSubRequest($uri, Request $request)
7878
{
79-
if (null !== $request) {
80-
$cookies = $request->cookies->all();
81-
$server = $request->server->all();
82-
83-
// the sub-request is internal
84-
$server['REMOTE_ADDR'] = '127.0.0.1';
85-
} else {
86-
$cookies = array();
87-
$server = array();
88-
}
79+
$cookies = $request->cookies->all();
80+
$server = $request->server->all();
81+
82+
// the sub-request is internal
83+
$server['REMOTE_ADDR'] = '127.0.0.1';
8984

9085
$subRequest = Request::create($uri, 'get', array(), $cookies, array(), $server);
91-
if (null !== $request && $session = $request->getSession()) {
86+
if ($session = $request->getSession()) {
9287
$subRequest->setSession($session);
9388
}
9489

src/Symfony/Component/HttpKernel/RenderingStrategy/EsiRenderingStrategy.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
*
2222
* @author Fabien Potencier <[email protected]>
2323
*/
24-
class EsiRenderingStrategy extends GeneratorAwareRenderingStrategy
24+
class EsiRenderingStrategy extends ProxyAwareRenderingStrategy
2525
{
2626
private $esi;
2727
private $defaultStrategy;
@@ -55,9 +55,9 @@ public function __construct(Esi $esi, RenderingStrategyInterface $defaultStrateg
5555
*
5656
* @see Symfony\Component\HttpKernel\HttpCache\ESI
5757
*/
58-
public function render($uri, Request $request = null, array $options = array())
58+
public function render($uri, Request $request, array $options = array())
5959
{
60-
if (null === $request || !$this->esi->hasSurrogateEsiCapability($request)) {
60+
if (!$this->esi->hasSurrogateEsiCapability($request)) {
6161
return $this->defaultStrategy->render($uri, $request, $options);
6262
}
6363

0 commit comments

Comments
 (0)