8000 merged branch fabpot/twig-render (PR #6386) · waibo/symfony@2cc51b0 · GitHub
[go: up one dir, main page]

Skip to content

Commit 2cc51b0

Browse files
committed
merged branch fabpot/twig-render (PR symfony#6386)
This PR was merged into the master branch. Commits ------- 163564b [WebProfilerBundle] replaced yaml_dump by json_encode to make the Web Profiler independent from the YAML component 1c92307 [WebProfilerBundle] fixed exception panel when no exception is thrown 00e08be [WebProfilerBundle] replaced usage of the render tag by the render function (to decouple the bundle from TwigBundle) 0e2418c [TwigBundle] added the HttpKernel extension to the default Twig loaded extensions f0d9be0 [TwigBridge] added an extension for the HttpKernel component Discussion ---------- Added an HttpKernelExtension in Twig bridge and used it in the WebProfiler The first commit introduces a new HttpKernelExtension in the Twig bridge that allows the rendering of a sub-request from a template (the code mostly comes from Silex, and will replace the code there at some point). The name `render` is probably not the best one as it does not really tell you what it does (the same goes for the `render` tag we have in Symfony2 by the way). Here is a list of possible names: * `render()` * `render_request()` * `request()` * `subrequest()` * `include_request()` I don't really like the last one, but it is (perhaps) consistent with the `include` tag/function in Twig. This new `render()` function is also a first step towards replacing the `render` tag (with support for ESI, SSI, ...). But it won't happen before we refactor the way it's managed now (a lot of the code is in the FrameworkBundle right now and that prevents Silex or Drupal to reuse it). The other commits make use of this new extension to make the Web Profiler truly independent from TwigBundle and FrameworkBundle.
2 parents 73c0397 + 163564b commit 2cc51b0

File tree

12 files changed

+208
-13
lines changed

12 files changed

+208
-13
lines changed
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
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\Bridge\Twig\Extension;
13+
14+
use Symfony\Component\HttpFoundation\Request;
15+
use Symfony\Component\HttpKernel\KernelEvents;
16+
use Symfony\Component\HttpKernel\HttpKernelInterface;
17+
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
18+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
19+
20+
/**
21+
* Provides integration with the HttpKernel component.
22+
*
23+
* @author Fabien Potencier <fabien@symfony.com>
24+
*/
25+
class HttpKernelExtension extends \Twig_Extension implements EventSubscriberInterface
26+
{
27+
private $kernel;
28+
private $request;
29+
30+
/**
31+
* Constructor.
32+
*
33+
* @param HttpKernelInterface $kernel A HttpKernelInterface install
34+
*/
35+
public function __construct(HttpKernelInterface $kernel)
36+
{
37+
$this->kernel = $kernel;
38+
}
39+
40+
public function getFunctions()
41+
{
42+
return array(
43+
'render' => new \Twig_Function_Method($this, 'render', array('needs_environment' => true, 'is_safe' => array('html'))),
44+
);
45+
}
46+
47+
/**
48+
* Renders a URI.
49+
*
50+
* @param \Twig_Environment $twig A \Twig_Environment instance
51+
* @param string $uri The URI to render
52+
*
53+
* @return string The Response content
54+
*/
55+
public function render(\Twig_Environment $twig, $uri)
56+
{
57+
if (null !== $this->request) {
58+
$cookies = $this->request->cookies->all();
59+
$server = $this->request->server->all();
60+
} else {
61+
$cookies = array();
62+
$server = array();
63+
}
64+
65+
$subRequest = Request::create($uri, 'get', array(), $cookies, array(), $server);
66+
if (null !== $this->request && $this->request->getSession()) {
67+
$subRequest->setSession($this->request->getSession());
68+
}
69+
70+
$response = $this->kernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST, false);
71+
72+
if (!$response->isSuccessful()) {
73+
throw new \RuntimeException(sprintf('Error when rendering "%s" (Status code is %s).', $subRequest->getUri(), $response->getStatusCode()));
74+
}
75+
76+
return $response->getContent();
77+
}
78+
79+
public function onKernelRequest(GetResponseEvent $event)
80+
{
81+
$this->request = $event->getRequest();
82+
}
83+
84+
public static function getSubscribedEvents()
85+
{
86+
return array(
87+
KernelEvents::REQUEST => array('onKernelRequest'),
88+
);
89+
}
90+
91+
public function getName()
92+
{
93+
return 'http_kernel';
94+
}
95+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
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\Bridge\Twig\Tests\Extension;
13+
14+
use Symfony\Bridge\Twig\Extension\HttpKernelExtension;
15+
use Symfony\Bridge\Twig\Tests\TestCase;
16+
use Symfony\Component\HttpFoundation\Response;
17+
use Symfony\Component\HttpKernel\HttpKernelInterface;
18+
19+
class HttpKernelExtensionTest extends TestCase
20+
{
21+
protected function setUp()
22+
{
23+
if (!class_exists('Symfony\Component\HttpKernel\HttpKernel')) {
24+
$this->markTestSkipped('The "HttpKernel" component is not available');
25+
}
26+
27+
if (!class_exists('Twig_Environment')) {
28+
$this->markTestSkipped('Twig is not available.');
29+
}
30+
}
31+
32+
public function testRenderWithoutMasterRequest()
33+
{
34+
$kernel = $this->getKernel($this->returnValue(new Response('foo')));
35+
36+
$this->assertEquals('foo', $this->renderTemplate($kernel));
37+
}
38+
39+
/**
40+
* @expectedException \Twig_Error_Runtime
41+
*/
42+
public function testRenderWithError()
43+
{
44+
$kernel = $this->getKernel($this->throwException(new \Exception('foo')));
45+
46+
$loader = new \Twig_Loader_Array(array('index' => '{{ render("foo") }}'));
47+
$twig = new \Twig_Environment($loader, array('debug' => true, 'cache' => false));
48+
$twig->addExtension(new HttpKernelExtension($kernel));
49+
50+
$this->renderTemplate($kernel);
51+
}
52+
53+
protected function getKernel($return)
54+
{
55+
$kernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface');
56+
$kernel
57+
->expects($this->once())
58+
->method('handle')
59+
->will($return)
60+
;
61+
62+
return $kernel;
63+
}
64+
65+
protected function renderTemplate(HttpKernelInterface $kernel, $template = '{{ render("foo") }}')
66+
{
67+
$loader = new \Twig_Loader_Array(array('index' => $template));
68+
$twig = new \Twig_Environment($loader, array('debug' => true, 'cache' => false));
69+
$twig->addExtension(new HttpKernelExtension($kernel));
70+
71+
return $twig->render('index');
72+
}
73+
}

src/Symfony/Bridge/Twig/composer.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
},
2222
"require-dev": {
2323
"symfony/form": "2.2.*",
24+
"symfony/http-kernel": "2.2.*",
2425
"symfony/routing": "2.2.*",
2526
"symfony/templating": "2.2.*",
2627
"symfony/translation": "2.2.*",
@@ -29,6 +30,7 @@
2930
},
3031
"suggest": {
3132
"symfony/form": "2.2.*",
33+
"symfony/http-kernel": "2.2.*",
3234
"symfony/routing": "2.2.*",
3335
"symfony/templating": "2.2.*",
3436
"symfony/translation": "2.2.*",

src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
<parameter key="twig.extension.routing.class">Symfony\Bridge\Twig\Extension\RoutingExtension</parameter>
1818
<parameter key="twig.extension.yaml.class">Symfony\Bridge\Twig\Extension\YamlExtension</parameter>
1919
<parameter key="twig.extension.form.class">Symfony\Bridge\Twig\Extension\FormExtension</parameter>
20+
<parameter key="twig.extension.httpkernel.class">Symfony\Bridge\Twig\Extension\HttpKernelExtension</parameter>
2021
<parameter key="twig.form.engine.class">Symfony\Bridge\Twig\Form\TwigRendererEngine</parameter>
2122
<parameter key="twig.form.renderer.class">Symfony\Bridge\Twig\Form\TwigRenderer</parameter>
2223
<parameter key="twig.translation.extractor.class">Symfony\Bridge\Twig\Translation\TwigExtractor</parameter>
@@ -87,6 +88,12 @@
8788
<tag name="twig.extension" />
8889
</service>
8990

91+
<service id="twig.extension.httpkernel" class="%twig.extension.httpkernel.class%">
92+
<tag name="twig.extension" />
93+
<tag name="kernel.event_subscriber" />
94+
<argument type="service" id="http_kernel" />
95+
</service>
96+
9097
<service id="twig.extension.form" class="%twig.extension.form.class%" public="false">
9198
<tag name="twig.extension" />
9299
<argument type="service" id="twig.form.renderer" />

src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,11 +166,10 @@ public function infoAction($about)
166166
*
167167
* @param Request $request The current HTTP Request
1681 10000 68
* @param string $token The profiler token
169-
* @param string $position The toolbar position (top, bottom, normal, or null -- use the configuration)
170169
*
171170
* @return Response A Response instance
172171
*/
173-
public function toolbarAction(Request $request, $token, $position = null)
172+
public function toolbarAction(Request $request, $token)
174173
{
175174
$session = $request->getSession();
176175

@@ -189,7 +188,8 @@ public function toolbarAction(Request $request, $token, $position = null)
189188
return new Response();
190189
}
191190

192-
if (null === $position) {
191+
// the toolbar position (top, bottom, normal, or null -- use the configuration)
192+
if (null === $position = $request->query->get('position')) {
193193
$position = $this->toolbarPosition;
194194
}
195195

src/Symfony/Bundle/WebProfilerBundle/Resources/config/routing/profiler.xml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
<default key="_controller">web_profiler.controller.profiler:searchAction</default>
99
</route>
1010

11+
<route id="_profiler_search_bar" pattern="/search_bar">
12+
<default key="_controller">web_profiler.controller.profiler:searchBarAction</default>
13+
</route>
14+
1115
<route id="_profiler_purge" pattern="/purge">
1216
<default key="_controller">web_profiler.controller.profiler:purgeAction</default>
1317
</route>
@@ -36,6 +40,18 @@
3640
<default key="_controller">web_profiler.controller.profiler:panelAction</default>
3741
</route>
3842

43+
<route id="_profiler_router" pattern="/{token}/router">
44+
<default key="_controller">web_profiler.controller.router:panelAction</default>
45+
</route>
46+
47+
<route id=< 10000 span class="pl-pds">"_profiler_exception" pattern="/{token}/exception">
48+
<default key="_controller">web_profiler.controller.exception:showAction</default>
49+
</route>
50+
51+
<route id="_profiler_exception_css" pattern="/{token}/exception.css">
52+
<default key="_controller">web_profiler.controller.exception:cssAction</default>
53+
</route>
54+
3955
<route id="_profiler_redirect" pattern="/">
4056
<default key="_controller">FrameworkBundle:Redirect:redirect</default>
4157
<default key="route">_profiler_search_results</default>

src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/exception.html.twig

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
{% extends '@WebProfiler/Profiler/layout.html.twig' %}
22

33
{% block head %}
4-
<style type="text/css">
5-
{% render 'web_profiler.controller.exception:cssAction' with { 'token': token } %}
6-
</style>
4+
{% if collector.hasexception %}
5+
<style type="text/css">
6+
{{ render(path('_profiler_exception_css', { 'token': token })) }}
7+
</style>
8+
{% endif %}
79
{{ parent() }}
810
{% endblock %}
911

@@ -28,7 +30,7 @@
2830
</p>
2931
{% else %}
3032
<div class="sf-reset">
31-
{% render 'web_profiler.controller.exception:showAction' with { 'token': token } %}
33+
{{ render(path('_profiler_exception', { 'token': token })) }}
3234
</div>
3335
{% endif %}
3436
{% endblock %}

src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/router.html.twig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@
1111
{% endblock %}
1212

1313
{% block panel %}
14-
{% render "web_profiler.controller.router:panelAction" with {'token': token} %}
14+
{{ render(path('_profiler_router', {'token': token})) }}
1515
{% endblock %}

src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/bag.html.twig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
{% for key in bag.keys|sort %}
1010
<tr>
1111
<th>{{ key }}</th>
12-
<td>{{ bag.get(key)|yaml_dump }}</td>
12+
<td>{{ bag.get(key)|json_encode }}</td>
1313
</tr>
1414
{% endfor %}
1515
</tbody>

src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/info.html.twig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
</div>
3535
</div>
3636
<div id="navigation">
37-
{% render 'web_profiler.controller.profiler:searchBarAction' %}
37+
{{ render(path('_profiler_search_bar')) }}
3838
{% include '@WebProfiler/Profiler/admin.html.twig' with { 'token': '' } only %}
3939
</div>
4040
</div>

0 commit comments

Comments
 (0)
0