$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')); } }