diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/Engine.php b/src/Symfony/Bundle/FrameworkBundle/Templating/Engine.php
index 202c0ce239ac..827c41598c4d 100755
--- a/src/Symfony/Bundle/FrameworkBundle/Templating/Engine.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Templating/Engine.php
@@ -27,7 +27,6 @@ class Engine extends BaseEngine
{
protected $container;
protected $escaper;
- protected $level;
/**
* Constructor.
@@ -39,7 +38,6 @@ class Engine extends BaseEngine
*/
public function __construct(ContainerInterface $container, LoaderInterface $loader, array $renderers = array(), $escaper = false)
{
- $this->level = 0;
$this->container = $container;
$this->escaper = $escaper;
@@ -61,8 +59,6 @@ public function __construct(ContainerInterface $container, LoaderInterface $load
public function render($name, array $parameters = array())
{
- ++$this->level;
-
list(, $options) = $this->splitTemplateName($name);
$renderer = $options['renderer'];
@@ -73,17 +69,10 @@ public function render($name, array $parameters = array())
}
if ('php' === $renderer) {
- // escape only once
- if (1 === $this->level && !isset($parameters['_data'])) {
- $parameters = $this->escapeParameters($parameters);
- }
+ $parameters = $this->escapeParameters($parameters);
}
- $content = parent::render($name, $parameters);
-
- --$this->level;
-
- return $content;
+ return parent::render($name, $parameters);
}
/**
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/EngineTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/EngineTest.php
index 230bdb0575aa..aa793581b8c3 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/EngineTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/EngineTest.php
@@ -13,9 +13,50 @@
use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
use Symfony\Bundle\FrameworkBundle\Templating\Engine;
+use Symfony\Component\Templating\Storage\StringStorage;
+use Symfony\Component\Templating\Storage\Storage;
+use Symfony\Component\Templating\Renderer\PhpRenderer;
+use Symfony\Component\OutputEscaper\Escaper;
+
+// simulate the rendering of another controller
+function foo($engine)
+{
+ return $engine->render('FooBundle:Foo:tpl1.php', array('foo' => 'foo
'));
+}
class EngineTest extends TestCase
{
+ public function testRenderEscaping()
+ {
+ $templates = array(
+ 'tpl1' => '',
+ 'tpl2' => 'render("FooBundle:Foo:tpl1.php", array("foo" => $foo)) ?>',
+ 'tpl3' => 'render("FooBundle:Foo:tpl1.php", array("foo" => "foo
")) ?>',
+ 'tpl4' => '',
+ );
+
+ $loader = $this->getMock('Symfony\Component\Templating\Loader\LoaderInterface');
+ $loader->expects($this->exactly(4))
+ ->method('load')
+ ->with($this->anything(), $this->anything())
+ ->will($this->onConsecutiveCalls(
+ new StringStorage($templates['tpl1']),
+ new StringStorage($templates['tpl2']),
+ new StringStorage($templates['tpl3']),
+ new StringStorage($templates['tpl4'])
+ ))
+ ;
+
+ $engine = new Engine($this->getContainerMock(), $loader, array('php' => new PhpRenderer()), 'htmlspecialchars');
+
+ $this->assertEquals('foo <br />', $engine->render('FooBundle:Foo:tpl1.php', array('foo' => 'foo
')));
+ $this->assertEquals('foo <br />', $engine->render('FooBundle:Foo:tpl1.php', array('foo' => 'foo
')));
+
+ $this->assertEquals('foo <br />foo <br />', $engine->render('FooBundle:Foo:tpl2.php', array('foo' => 'foo
')));
+ $this->assertEquals('foo <br />foo <br />', $engine->render('FooBundle:Foo:tpl3.php', array('foo' => 'foo
')));
+ $this->assertEquals('foo <br />foo <br />', $engine->render('FooBundle:Foo:tpl4.php', array('foo' => 'foo
')));
+ }
+
/**
* @dataProvider getSplitTemplateNameTests
*/
diff --git a/src/Symfony/Component/OutputEscaper/Escaper.php b/src/Symfony/Component/OutputEscaper/Escaper.php
index f929270b8ce0..1ef1a53280ea 100644
--- a/src/Symfony/Component/OutputEscaper/Escaper.php
+++ b/src/Symfony/Component/OutputEscaper/Escaper.php
@@ -206,6 +206,9 @@ static public function getCharset()
/**
* Adds a named escaper.
*
+ * Warning: An escaper must be able to deal with
+ * double-escaping correctly.
+ *
* @param string $name The escaper name
* @param mixed $escaper A PHP callable
*/
@@ -262,7 +265,7 @@ function ($value)
{
// Numbers and boolean values get turned into strings which can cause problems
// with type comparisons (e.g. === or is_int() etc).
- return is_string($value) ? htmlspecialchars($value, ENT_QUOTES, Escaper::getCharset()) : $value;
+ return is_string($value) ? htmlspecialchars($value, ENT_QUOTES, Escaper::getCharset(), false) : $value;
},
'entities' =>
@@ -276,7 +279,7 @@ function ($value)
{
// Numbers and boolean values get turned into strings which can cause problems
// with type comparisons (e.g. === or is_int() etc).
- return is_string($value) ? htmlentities($value, ENT_QUOTES, Escaper::getCharset()) : $value;
+ return is_string($value) ? htmlentities($value, ENT_QUOTES, Escaper::getCharset(), false) : $value;
},
'raw' =>