$template, 'embedded' => '{% block content %}{% endblock %}']), ['autoescape' => $autoescape]);
$this->assertSame($escaperClasses, substr_count($env->compileSource($env->getLoader()->getSourceContext('index')), 'private \Twig\Runtime\EscaperRuntime $escaper;'));
$this->assertSame($expected, $env->render('index', ['foo' => '
']));
}
public static function provideTemplates(): iterable
{
yield 'autoescaped print' => ['html', '{{ foo }}', 1, '<br>'];
yield 'print marked as safe' => ['html', '{{ foo|raw }}', 0, '
'];
yield 'autoescaping disabled' => [false, '{{ foo }}{# not autoescaped #}', 0, '
'];
yield 'explicit escape filter' => [false, '{{ foo|e }}', 1, '<br>'];
yield 'autoescape tag' => [false, '{% autoescape "html" %}{{ foo }}{% endautoescape %}', 1, '<br>'];
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('
', $env->render('index.txt', ['foo' => '
']));
$this->assertSame('<br>', $env->render('index.html', ['foo' => '
']));
}
public function testEscapeFilterAddedByALaterVisitorStillEscapes(): void
{
$env = new Environment(new ArrayLoader(['index' => '{{ "
" }}']), ['autoescape' => false]);
$env->addExtension(new class extends AbstractExtension {
public function getNodeVisitors(): array
{
return [new class implements NodeVisitorInterface {
public function enterNode(Node $node, Environment $env): Node
{
return $node;
}
public function leaveNode(Node $node, Environment $env): ?Node
{
if (!$node instanceof PrintNode) {
return $node;
}
$filter = $env->getFilter('escape');
$class = $filter->getNodeClass();
return new PrintNode(new $class($node->getNode('expr'), $filter, new Nodes([new ConstantExpression('html', 1)]), 1), 1);
}
public function getPriority(): int
{
return 10;
}
}];
}
});
$this->assertSame('<br>', $env->render('index'));
}
}