Twig 3.25.0 released
Twig 3.25.0 ships with a new needs_is_sandboxed option that lets
filters, functions, and tests adapt their behavior when running inside a
sandbox, makes the compiled output of templates using {% embed %}
deterministic across runs, and removes a long-standing limitation that
prevented overriding EscaperRuntime via a custom runtime loader.
Sandbox-aware filters, functions, and tests
Until now, a Twig callable had no built-in way to know whether the template calling it was running in a sandbox. Filters, functions, and tests that needed to behave differently in trusted versus untrusted contexts had to inspect the environment manually and replicate the sandbox detection logic.
Twig 3.25 introduces a new needs_is_sandboxed option. When set to
true, Twig passes the current sandbox state as a boolean to the
callable, after the charset, the environment, and the context if those are
also requested:
1 2 3 4 5 6 7 8 9
use Twig\TwigFilter;
$filter = new TwigFilter('rot13', function (bool $sandboxed, string $text) {
if ($sandboxed) {
// adjust the behavior when running in a sandboxed template
}
return str_rot13($text);
}, ['needs_is_sandboxed' => true]);
The same option is available on TwigFunction and TwigTest, and on
the #[AsTwigFilter], #[AsTwigFunction], and #[AsTwigTest]
attributes via a needsIsSandboxed named argument.
The flag reflects the effective sandbox state for the current template
source, so it correctly accounts for both the global sandbox state and any
SourcePolicy you may have configured.
Deterministic embed classes
Templates using {% embed %} now produce stable compiled output across
runs, which makes it possible to ship reproducible, pre-compiled Twig
builds. No change is required on your side.
Overridable EscaperRuntime
You can now substitute your own EscaperRuntime implementation through
any runtime loader, including FactoryRuntimeLoader and Symfony's
ContainerRuntimeLoader:
1 2 3 4 5 6 7 8 9
use Twig\Environment;
use Twig\Loader\ArrayLoader;
use Twig\Runtime\EscaperRuntime;
use Twig\RuntimeLoader\FactoryRuntimeLoader;
$twig = new Environment(new ArrayLoader());
$twig->addRuntimeLoader(new FactoryRuntimeLoader([
EscaperRuntime::class => static fn () => new MyEscaperRuntime(),
]));
Symfony 8.1's TwigBundle already builds on this: EscaperRuntime is
now registered as the twig.runtime.escaper service, and a new
twig.safe_class resource tag lets any bundle mark a class as safe
without having to decorate the environment configurator:
1 2
$services->set(InvoiceNumber::class)
->resourceTag('twig.safe_class', ['strategy' => 'html']);