mirror of
https://github.com/twigphp/Twig.git
synced 2026-10-05 11:27:26 +00:00
Reset the escaping state when compiling a new template after a compilation error
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
# 3.30.1 (2026-XX-XX)
|
||||
|
||||
* Reject a deprecated `Template` instance created by another environment in `Environment::resolveTemplate()`
|
||||
* Fix a compilation error inside an `autoescape` tag leaking its escaping strategy into the next compiled template
|
||||
* Speed up reading object attributes backed by getters or class constants
|
||||
* Fix the sandbox not reporting the line of a rejected `guard` tag
|
||||
|
||||
|
||||
@@ -51,12 +51,14 @@ final class EscaperNodeVisitor implements NodeVisitorInterface
|
||||
public function enterNode(Node $node, Environment $env): Node
|
||||
{
|
||||
if ($node instanceof ModuleNode) {
|
||||
$this->defaultStrategy = false;
|
||||
if ($env->hasExtension(EscaperExtension::class) && $defaultStrategy = $env->getExtension(EscaperExtension::class)->getDefaultStrategy($node->getTemplateName())) {
|
||||
$this->defaultStrategy = $defaultStrategy;
|
||||
}
|
||||
$node->setAttribute('strategy', \is_string($this->defaultStrategy) ? $this->defaultStrategy : false);
|
||||
$this->safeVars = [];
|
||||
$this->blocks = [];
|
||||
$this->statusStack = [];
|
||||
$this->usesEscaper = false;
|
||||
} elseif ($node instanceof AutoEscapeNode) {
|
||||
$this->statusStack[] = $node->getAttribute('value');
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Twig\Tests\NodeVisitor;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Twig\Environment;
|
||||
use Twig\Error\Error;
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\Loader\ArrayLoader;
|
||||
use Twig\Node\Expression\ConstantExpression;
|
||||
@@ -21,6 +22,7 @@ use Twig\Node\Node;
|
||||
use Twig\Node\Nodes;
|
||||
use Twig\Node\PrintNode;
|
||||
use Twig\NodeVisitor\NodeVisitorInterface;
|
||||
use Twig\TwigFilter;
|
||||
|
||||
class EscaperTest extends TestCase
|
||||
{
|
||||
@@ -46,6 +48,32 @@ class EscaperTest extends TestCase
|
||||
yield 'escaping in an embedded template only' => [false, '{% embed "embedded" %}{% block content %}{{ foo|e }}{% endblock %}{% endembed %}', 1, '<br>'];
|
||||
}
|
||||
|
||||
public function testCompilationErrorInsideAnAutoescapeTagDoesNotAffectTheNextTemplate(): void
|
||||
{
|
||||
$env = new Environment(new ArrayLoader([
|
||||
'broken.html' => '{% autoescape false %}{{ foo|failing|nl2br }}{% endautoescape %}',
|
||||
'index.html' => '{{ foo }}',
|
||||
'index.txt' => '{{ foo }}',
|
||||
]), ['autoescape' => 'name']);
|
||||
$env->addExtension(new class extends AbstractExtension {
|
||||
public function getFilters(): array
|
||||
{
|
||||
return [new TwigFilter('failing', static fn ($value) => $value, ['is_safe_callback' => static function (): array {
|
||||
throw new \LogicException('Unable to compute the safety of the filter.');
|
||||
}])];
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
$env->load('broken.html');
|
||||
$this->fail('Compiling the template should fail.');
|
||||
} catch (Error) {
|
||||
}
|
||||
|
||||
$this->assertSame('<br>', $env->render('index.txt', ['foo' => '<br>']));
|
||||
$this->assertSame('<br>', $env->render('index.html', ['foo' => '<br>']));
|
||||
}
|
||||
|
||||
public function testEscapeFilterAddedByALaterVisitorStillEscapes(): void
|
||||
{
|
||||
$env = new Environment(new ArrayLoader(['index' => '{{ "<br>" }}']), ['autoescape' => false]);
|
||||
|
||||
Reference in New Issue
Block a user