Remove deprecated code

This commit is contained in:
Fabien Potencier
2026-06-11 08:16:23 +02:00
parent 46a11071c2
commit eb8ca3b887
14 changed files with 54 additions and 223 deletions
+3
View File
@@ -4,6 +4,9 @@
* Always allow printing a `Markup` object in a sandbox, whatever the security policy is
* Remove the `Twig\Sandbox\SourcePolicyInterface` interface and the corresponding argument of `Twig\Extension\SandboxExtension::__construct()`
* Enforce the `parent`, `block`, and `attribute` functions against the sandbox `allowedFunctions` allow-list
* Enforce tests against the sandbox `allowedTests` allow-list and add the `$allowedTests` argument to `Twig\Sandbox\SecurityPolicy::__construct()`
* Add a fourth `array $tests` argument to `Twig\Sandbox\SecurityPolicyInterface::checkSecurity()`
* Throw a `SyntaxError` when an `extends`, `use`, or `macro` tag is not at the root of a template
# 4.0.0 alpha 1 (2026-05-17)
+13 -19
View File
@@ -42,11 +42,10 @@ Everything else won't be allowed and will generate a
.. note::
The ``allowedTests`` argument is available since Twig 3.28 (in earlier
versions all tests were always allowed). Most built-in tests (``empty``,
``defined``, ``even``, ``same as``, ``iterable``, etc.) are always allowed
and do not need to be listed. Only custom tests and the built-in
``constant`` test must be allow-listed like filters and functions.
Most built-in tests (``empty``, ``defined``, ``even``, ``same as``,
``iterable``, etc.) are always allowed and do not need to be listed. Only
custom tests and the built-in ``constant`` test must be allow-listed like
filters and functions.
.. note::
@@ -149,12 +148,11 @@ iterated items). That transitive behavior is documented separately under
the sandbox model. The criteria above are about what the item itself
exposes, not about how its arguments behave.
Built-ins That Will Be Always Allowed in 4.0
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Built-ins That Are Always Allowed
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The following Twig built-ins meet the criteria above and will have the
``always_allowed_in_sandbox`` flag set in Twig 4.0. They still need to be
explicitly allow-listed in 3.x.
The following Twig built-ins meet the criteria above and have the
``always_allowed_in_sandbox`` flag set, so they never need to be allow-listed.
* Tags: ``apply``, ``block``, ``do``, ``for``, ``guard``, ``if``, ``macro``,
``set``, ``types``, ``with``.
@@ -165,18 +163,14 @@ explicitly allow-listed in 3.x.
``title``, ``trim``, ``upper``, ``url_encode``.
* Functions: ``cycle``, ``max``, ``min``.
When upgrading to 4.0, you can drop these names from your ``SecurityPolicy``
allow-lists. Leaving them in is harmless: listing a name that is always
allowed has no effect.
Listing one of these names in your ``SecurityPolicy`` is harmless: it has no
effect.
The corresponding built-in tests (``defined``, ``divisible by``, ``empty``,
``even``, ``iterable``, ``mapping``, ``none``, ``null``, ``odd``, ``same as``,
``sequence``, ``true``) are **already** flagged as always allowed since Twig
3.28, so they never need to be allow-listed. This is safe because tests were
never enforced by the sandbox before 3.28: flagging them keeps existing
templates working unchanged. The ``constant`` test is the exception: it reaches
into the PHP runtime, so it is not always allowed and must be allow-listed (it
is still implicitly allowed in 3.x with a deprecation, and rejected in 4.0).
``sequence``, ``true``) are also always allowed, so they never need to be
allow-listed. The ``constant`` test is the exception: it reaches into the PHP
runtime, so it is not always allowed and must be allow-listed.
Enabling the Sandbox
--------------------
-7
View File
@@ -1,12 +1,5 @@
parameters:
ignoreErrors:
- # The "$tests" parameter is documented now and will be part of the signature in 4.0
message: '#^PHPDoc tag @param references unknown parameter\: \$tests$#'
identifier: parameter.notFound
count: 1
path: src/Sandbox/SecurityPolicyInterface.php
- # 2 parameters will be required
message: '#^Method Twig\\Node\\IncludeNode\:\:addGetTemplate\(\) invoked with 2 parameters, 1 required\.$#'
identifier: arguments.count
+2 -20
View File
@@ -65,29 +65,11 @@ final class SandboxExtension extends AbstractExtension
return $this->policy;
}
public function checkSecurity($tags, $filters, $functions, $tests = [], $source = null): void
public function checkSecurity($tags, $filters, $functions, $tests = [], ?Source $source = null): void
{
// BC: previous signature was checkSecurity($tags, $filters, $functions, ?Source $source = null);
// detect a legacy call where the 4th positional argument was the Source.
if ($tests instanceof Source || (null === $tests && \func_num_args() < 5)) {
trigger_deprecation('twig/twig', '3.28', 'Passing a "Twig\Source" as the 4th argument of "%s()" is deprecated; pass an array of tests instead.', __METHOD__);
$source = $tests;
$tests = [];
}
if (!$this->isSandboxed($source)) {
return;
}
if ((new \ReflectionMethod($this->policy, 'checkSecurity'))->getNumberOfParameters() >= 4) {
if ($this->isSandboxed($source)) {
$this->policy->checkSecurity($tags, $filters, $functions, $tests);
return;
}
trigger_deprecation('twig/twig', '3.28', 'The "%s::checkSecurity()" method will take a 4th "array $tests" argument in 4.0; not declaring it is deprecated.', $this->policy::class);
$this->policy->checkSecurity($tags, $filters, $functions);
}
public function checkMethodAllowed($obj, $method, int $lineno = -1, ?Source $source = null): void
+1 -5
View File
@@ -31,12 +31,8 @@ class CheckSecurityNode extends Node
* @param array<string, int> $usedFunctions
* @param array<string, int> $usedTests
*/
public function __construct(array $usedFilters, array $usedTags, array $usedFunctions, array $usedTests = [])
public function __construct(array $usedFilters, array $usedTags, array $usedFunctions, array $usedTests)
{
if (\func_num_args() < 4) {
trigger_deprecation('twig/twig', '3.28', 'Not passing the "$usedTests" argument to "%s::__construct()" is deprecated; it will be required in 4.0.', static::class);
}
$this->usedFilters = $usedFilters;
$this->usedTags = $usedTags;
$this->usedFunctions = $usedFunctions;
+1 -1
View File
@@ -159,7 +159,7 @@ final class CorrectnessNodeVisitor implements NodeVisitorInterface
}
if (!isset($this->rootNodes[$node])) {
trigger_deprecation('twig/twig', '3.27', 'Using the "%s" tag outside the root of a template is deprecated in %s at line %d.', $node->getNodeTag(), $node->getSourceContext()->getName(), $node->getTemplateLine());
throw new SyntaxError(\sprintf('The "%s" tag can only be used at the root of a template.', $node->getNodeTag()), $node->getTemplateLine(), $node->getSourceContext());
}
}
+2 -11
View File
@@ -42,7 +42,6 @@ final class SecurityPolicy implements SecurityPolicyInterface
* @var string[]
*/
private array $allowedTests;
private bool $strict = false;
public function __construct(array $allowedTags = [], array $allowedFilters = [], array $allowedMethods = [], array $allowedProperties = [], array $allowedFunctions = [], array $allowedTests = [])
{
@@ -100,12 +99,8 @@ final class SecurityPolicy implements SecurityPolicyInterface
{
}
public function checkSecurity($tags, $filters, $functions, array $tests = []): void
public function checkSecurity($tags, $filters, $functions, array $tests): void
{
if (\func_num_args() < 4) {
trigger_deprecation('twig/twig', '3.28', 'Not passing the "$tests" argument to "%s::checkSecurity()" is deprecated; it will be required in 4.0.', static::class);
}
foreach ($tags as $tag) {
if (!\in_array($tag, $this->allowedTags, true)) {
throw new SecurityNotAllowedTagError(\sprintf('Tag "%s" is not allowed.', $tag), $tag);
@@ -126,11 +121,7 @@ final class SecurityPolicy implements SecurityPolicyInterface
foreach ($tests as $test) {
if (!\in_array($test, $this->allowedTests, true)) {
if (!$this->strict) {
trigger_deprecation('twig/twig', '3.28', 'The "%s" test is always allowed in sandboxes, but won\'t be in 4.0, please enable it explicitly in your sandbox policy if needed (or enable strict mode on the security policy to opt-in to the 4.0 behavior now).', $test);
} else {
throw new SecurityNotAllowedTestError(\sprintf('Test "%s" is not allowed.', $test), $test);
}
throw new SecurityNotAllowedTestError(\sprintf('Test "%s" is not allowed.', $test), $test);
}
}
}
+1 -1
View File
@@ -26,7 +26,7 @@ interface SecurityPolicyInterface
*
* @throws SecurityError
*/
public function checkSecurity($tags, $filters, $functions/* , array $tests */): void;
public function checkSecurity($tags, $filters, $functions, array $tests): void;
/**
* @param object $obj
+21 -144
View File
@@ -46,7 +46,6 @@ use Twig\Sandbox\SecurityPolicyInterface;
use Twig\Source;
use Twig\Token;
use Twig\TokenParser\AbstractTokenParser;
use Twig\TokenParser\TokenParserInterface;
use Twig\TwigFilter;
use Twig\TwigFunction;
use Twig\TwigTest;
@@ -217,7 +216,7 @@ class SandboxTest extends TestCase
#[DataProvider('getStrictSandboxRejectsGrandfatheredTagsTests')]
public function testStrictSandboxRejectsGrandfatheredTags(string $tag, string $template)
{
$twig = $this->getEnvironment(true, [], self::$templates, [], [], [], [], [], true);
$twig = $this->getEnvironment(true, [], self::$templates, [], [], [], [], []);
$this->expectException(SecurityNotAllowedTagError::class);
$this->expectExceptionMessage(\sprintf('Tag "%s" is not allowed', $tag));
@@ -231,13 +230,10 @@ class SandboxTest extends TestCase
yield ['use', '{% use "1_empty" %}'];
}
/**
* @dataProvider getStrictSandboxRejectsGrandfatheredFunctionsTests
*/
#[DataProvider('getStrictSandboxRejectsGrandfatheredFunctionsTests')]
public function testStrictSandboxRejectsGrandfatheredFunctions(string $function, string $templateName, array $extraTemplates, array $allowedTags, array $context)
{
$twig = $this->getEnvironment(true, [], $extraTemplates, $allowedTags, [], [], [], [], true);
$twig = $this->getEnvironment(true, [], $extraTemplates, $allowedTags, [], [], [], []);
$this->expectException(SecurityNotAllowedFunctionError::class);
$this->expectExceptionMessage(\sprintf('Function "%s" is not allowed', $function));
@@ -289,32 +285,17 @@ class SandboxTest extends TestCase
[],
[],
['parent', 'attribute'],
null,
true,
);
$this->assertSame('PARENT CHILD - OK', $twig->load('child')->render(['data' => ['x' => 'OK']]));
}
public function testStrictModeCanBeEnabledViaSetterAfterConstruction()
{
$policy = new SecurityPolicy([], [], [], [], []);
$policy->setStrict(true);
$this->expectException(SecurityNotAllowedTagError::class);
$policy->checkSecurity(['extends'], [], [], []);
}
/**
* @dataProvider getAlwaysAllowedCoreTests
*/
#[DataProvider('getAlwaysAllowedCoreTests')]
public function testSandboxAllowsAlwaysAllowedCoreTests(string $template)
{
// the safe built-in tests are always allowed in a sandbox (they carry
// the `always_allowed_in_sandbox` flag), so they need neither an
// allow-list entry nor strict mode to be opted out of
$twig = $this->getEnvironment(true, [], self::$templates, [], [], [], [], [], true);
// the `always_allowed_in_sandbox` flag), so they need no allow-list entry
$twig = $this->getEnvironment(true, [], self::$templates, [], [], [], [], []);
$this->assertSame('y', $twig->createTemplate($template, 'index')->render([]));
}
@@ -335,43 +316,9 @@ class SandboxTest extends TestCase
yield ['{{ {"a": 1} is mapping ? "y" }}'];
}
/**
* @group legacy
*/
#[Group('legacy')]
public function testSandboxForConstantTest()
{
// unlike the other built-in tests, "constant" reaches into the PHP
// runtime, so it is not always allowed and is deprecated until 4.0
$this->expectDeprecation('Since twig/twig 3.28: The "constant" test is always allowed in sandboxes, but won\'t be in 4.0, please enable it explicitly in your sandbox policy if needed (or enable strict mode on the security policy to opt-in to the 4.0 behavior now).');
$twig = $this->getEnvironment(true, [], ['index' => '{{ 1 is constant("PHP_INT_MAX") ? "y" }}']);
$twig->load('index')->render([]);
}
/**
* @group legacy
*/
#[Group('legacy')]
public function testSandboxForUserDefinedTest()
{
$this->expectDeprecation('Since twig/twig 3.28: The "unsafe" test is always allowed in sandboxes, but won\'t be in 4.0, please enable it explicitly in your sandbox policy if needed (or enable strict mode on the security policy to opt-in to the 4.0 behavior now).');
$called = 0;
$twig = $this->getEnvironment(true, [], ['index' => '{{ "x" is unsafe ? "y" }}']);
$twig->addTest(new TwigTest('unsafe', static function ($value) use (&$called): bool {
++$called;
return true;
}));
$this->assertSame('y', $twig->load('index')->render([]));
$this->assertSame(1, $called);
}
public function testSandboxAllowsAllowListedTest()
{
$twig = $this->getEnvironment(true, [], ['index' => '{{ "x" is unsafe ? "y" }}'], [], [], [], [], [], false, ['unsafe']);
$twig = $this->getEnvironment(true, [], ['index' => '{{ "x" is unsafe ? "y" }}'], [], [], [], [], [], ['unsafe']);
$twig->addTest(new TwigTest('unsafe', static fn ($v): bool => true));
$this->assertSame('y', $twig->load('index')->render([]));
@@ -380,7 +327,7 @@ class SandboxTest extends TestCase
public function testStrictSandboxRejectsConstantTest()
{
// "constant" is the only built-in test that is not always allowed
$twig = $this->getEnvironment(true, [], ['index' => '{{ 1 is constant("PHP_INT_MAX") ? "y" }}'], [], [], [], [], [], true);
$twig = $this->getEnvironment(true, [], ['index' => '{{ 1 is constant("PHP_INT_MAX") ? "y" }}'], [], [], [], [], []);
$this->expectException(SecurityNotAllowedTestError::class);
$this->expectExceptionMessage('Test "constant" is not allowed');
@@ -390,14 +337,14 @@ class SandboxTest extends TestCase
public function testStrictSandboxStillAllowsAllowListedTest()
{
$twig = $this->getEnvironment(true, [], ['index' => '{{ 1 is constant("PHP_INT_MAX") ? "y" : "n" }}'], [], [], [], [], [], true, ['constant']);
$twig = $this->getEnvironment(true, [], ['index' => '{{ 1 is constant("PHP_INT_MAX") ? "y" : "n" }}'], [], [], [], [], [], ['constant']);
$this->assertSame('n', $twig->load('index')->render([]));
}
public function testStrictSandboxRejectsUserDefinedTest()
{
$twig = $this->getEnvironment(true, [], ['index' => '{{ "x" is unsafe ? "y" }}'], [], [], [], [], [], true);
$twig = $this->getEnvironment(true, [], ['index' => '{{ "x" is unsafe ? "y" }}'], [], [], [], [], []);
$twig->addTest(new TwigTest('unsafe', static fn ($v): bool => true));
$this->expectException(SecurityNotAllowedTestError::class);
@@ -411,16 +358,16 @@ class SandboxTest extends TestCase
// `{% if %}`, ternary, `?:`, `??`, and `|default` conditions are coerced
// to a boolean through `true`/`defined`/`null` tests that the compiler
// injects; the template author never wrote them and they are always
// allowed, so they must work even in strict mode with no test allow-listed
// allowed, so they must work with no test allow-listed
$template = "{% if x %}a{% endif %}{{ y ? 'b' : 'c' }}{{ z ?: 'd' }}{{ w ?? 'e' }}{{ v|default('f') }}";
$twig = $this->getEnvironment(true, [], ['index' => $template], ['if'], ['default'], [], [], [], true);
$twig = $this->getEnvironment(true, [], ['index' => $template], ['if'], ['default'], [], [], []);
$this->assertSame('acdef', $twig->load('index')->render(['x' => true, 'y' => false]));
}
public function testStrictSandboxRejectedTestCarriesSourceAndLine()
{
$twig = $this->getEnvironment(true, [], ['index' => "{{ 1 }}\n{{ 1 is constant('PHP_INT_MAX') ? 'y' }}"], [], [], [], [], [], true);
$twig = $this->getEnvironment(true, [], ['index' => "{{ 1 }}\n{{ 1 is constant('PHP_INT_MAX') ? 'y' }}"], [], [], [], [], []);
try {
$twig->load('index')->render([]);
@@ -432,10 +379,9 @@ class SandboxTest extends TestCase
}
}
public function testStrictModeRejectsTestsViaSetter()
public function testSandboxRejectsUnallowedTestViaSecurityPolicy()
{
$policy = new SecurityPolicy([], [], [], [], []);
$policy->setStrict(true);
$this->expectException(SecurityNotAllowedTestError::class);
$policy->checkSecurity([], [], [], ['empty']);
@@ -444,7 +390,6 @@ class SandboxTest extends TestCase
public function testAllowedTestsCanBeUpdatedViaSetter()
{
$policy = new SecurityPolicy([], [], [], [], []);
$policy->setStrict(true);
$policy->setAllowedTests(['empty']);
// does not throw
@@ -454,58 +399,6 @@ class SandboxTest extends TestCase
$policy->checkSecurity([], [], [], ['null']);
}
/**
* @group legacy
*/
#[Group('legacy')]
public function testLegacySecurityPolicyWithoutTestsParameterTriggersDeprecation()
{
$this->expectDeprecation('Since twig/twig 3.28: The "Twig\Tests\Extension\LegacySandboxSecurityPolicy::checkSecurity()" method will take a 4th "array $tests" argument in 4.0; not declaring it is deprecated.');
$loader = new ArrayLoader(['index' => '{{ "x" is unsafe ? "y" }}']);
$twig = new Environment($loader, ['debug' => true, 'cache' => false, 'autoescape' => false]);
$twig->addExtension(new SandboxExtension(new LegacySandboxSecurityPolicy(), true));
$twig->addTest(new TwigTest('unsafe', static fn ($v): bool => true));
// legacy policies silently allow tests (no security regression vs. today)
$this->assertSame('y', $twig->load('index')->render([]));
}
/**
* @group legacy
*/
#[Group('legacy')]
public function testLegacyCheckSecurityCallWithSourceAs4thArgumentTriggersDeprecation()
{
$this->expectDeprecation('Since twig/twig 3.28: Passing a "Twig\Source" as the 4th argument of "Twig\Extension\SandboxExtension::checkSecurity()" is deprecated; pass an array of tests instead.');
$policy = new SecurityPolicy([], [], [], [], []);
$ext = new SandboxExtension($policy, true);
$ext->checkSecurity([], [], [], new Source('', 'index'));
}
/**
* @group legacy
*/
#[Group('legacy')]
public function testLegacyCheckSecurityNodeWithoutUsedTestsTriggersDeprecation()
{
$this->expectDeprecation('Since twig/twig 3.28: Not passing the "$usedTests" argument to "Twig\Node\CheckSecurityNode::__construct()" is deprecated; it will be required in 4.0.');
new \Twig\Node\CheckSecurityNode([], [], []);
}
/**
* @group legacy
*/
#[Group('legacy')]
public function testLegacySecurityPolicyCheckSecurityWithoutTestsArgTriggersDeprecation()
{
$this->expectDeprecation('Since twig/twig 3.28: Not passing the "$tests" argument to "Twig\Sandbox\SecurityPolicy::checkSecurity()" is deprecated; it will be required in 4.0.');
(new SecurityPolicy([], [], [], [], []))->checkSecurity([], [], []);
}
public function testSandboxWithInheritance()
{
$twig = $this->getEnvironment(true, [], self::$templates, ['extends', 'block']);
@@ -890,7 +783,7 @@ class SandboxTest extends TestCase
public function testSandboxBlocksToStringOnIsConstantTestArgument()
{
$twig = $this->getEnvironment(true, [], ['index' => '{% if "x" is constant(obj) %}LEAK{% endif %}'], ['if'], [], [], [], [], false, ['constant']);
$twig = $this->getEnvironment(true, [], ['index' => '{% if "x" is constant(obj) %}LEAK{% endif %}'], ['if'], [], [], [], [], ['constant']);
try {
$twig->load('index')->render(self::$params);
$this->fail('Sandbox throws a SecurityError exception if __toString is called on a constant test argument');
@@ -926,7 +819,7 @@ class SandboxTest extends TestCase
#[DataProvider('getSandboxAllowedToStringTests')]
public function testSandboxAllowedToString($template, $output)
{
$twig = $this->getEnvironment(true, [], ['index' => $template], ['set', 'do'], [], [FooObject::class => ['foo', 'getAnotherFooObject']], [], [], false, ['constant']);
$twig = $this->getEnvironment(true, [], ['index' => $template], ['set', 'do'], [], [FooObject::class => ['foo', 'getAnotherFooObject']], [], [], ['constant']);
$this->assertEquals($output, $twig->load('index')->render(self::$params));
}
@@ -1697,17 +1590,16 @@ EOF
$policy->setStrict(true);
$policy->setStrict(false);
// 4.0 behavior is the default and unaffected by setStrict()
// sandbox rejection is the default and unaffected by setStrict()
$this->expectException(SecurityNotAllowedTagError::class);
$policy->checkSecurity(['extends'], [], []);
$policy->checkSecurity(['extends'], [], [], []);
}
protected function getEnvironment($sandboxed, $options, $templates, $tags = [], $filters = [], $methods = [], $properties = [], $functions = [], bool $strict = false, array $tests = [])
protected function getEnvironment($sandboxed, $options, $templates, $tags = [], $filters = [], $methods = [], $properties = [], $functions = [], array $tests = [])
{
$loader = new ArrayLoader($templates);
$twig = new Environment($loader, array_merge(['debug' => true, 'cache' => false, 'autoescape' => false], $options));
$policy = new SecurityPolicy($tags, $filters, $methods, $properties, $functions, $tests);
$policy->setStrict($strict);
$twig->addExtension(new SandboxExtension($policy, $sandboxed));
return $twig;
@@ -1746,7 +1638,7 @@ EOF
public function testNeedsIsSandboxedTestReceivesTrueWhenSandboxed()
{
$twig = $this->getEnvironment(true, [], ['index' => '{{ "foo" is sandbox_aware ? "on" : "off" }}'], [], [], [], [], [], false, ['sandbox_aware']);
$twig = $this->getEnvironment(true, [], ['index' => '{{ "foo" is sandbox_aware ? "on" : "off" }}'], [], [], [], [], [], ['sandbox_aware']);
$twig->addTest(new TwigTest('sandbox_aware', static function (bool $isSandboxed, string $value) {
return $isSandboxed && 'foo' === $value;
}, ['needs_is_sandboxed' => true]));
@@ -1802,7 +1694,7 @@ EOF
public function testAlwaysAllowedInSandboxTestBypassesAllowList()
{
$twig = $this->getEnvironment(true, [], ['index' => '{{ 4 is safe_even ? "yes" : "no" }}'], [], [], [], [], [], true);
$twig = $this->getEnvironment(true, [], ['index' => '{{ 4 is safe_even ? "yes" : "no" }}'], [], [], [], [], []);
$twig->addTest(new TwigTest('safe_even', static fn ($value) => 0 === $value % 2, ['always_allowed_in_sandbox' => true]));
$this->assertSame('yes', $twig->load('index')->render([]));
@@ -1810,7 +1702,7 @@ EOF
public function testAlwaysAllowedInSandboxTestStillEnforcedWhenFlagNotSet()
{
$twig = $this->getEnvironment(true, [], ['index' => '{{ 4 is gated_even ? "yes" : "no" }}'], [], [], [], [], [], true);
$twig = $this->getEnvironment(true, [], ['index' => '{{ 4 is gated_even ? "yes" : "no" }}'], [], [], [], [], []);
$twig->addTest(new TwigTest('gated_even', static fn ($value) => 0 === $value % 2));
$this->expectException(SecurityNotAllowedTestError::class);
@@ -2100,7 +1992,7 @@ class GatedSandboxTokenParser extends AbstractTokenParser
class DenyEverythingSecurityPolicy implements SecurityPolicyInterface
{
public function checkSecurity($tags, $filters, $functions): void
public function checkSecurity($tags, $filters, $functions, array $tests): void
{
}
@@ -2114,18 +2006,3 @@ class DenyEverythingSecurityPolicy implements SecurityPolicyInterface
throw new SecurityNotAllowedPropertyError(\sprintf('Calling "%s" property on a "%s" object is not allowed.', $property, $obj::class), $obj::class, $property);
}
}
class LegacySandboxSecurityPolicy implements SecurityPolicyInterface
{
public function checkSecurity($tags, $filters, $functions): void
{
}
public function checkMethodAllowed($obj, $method): void
{
}
public function checkPropertyAllowed($obj, $property): void
{
}
}
@@ -1,7 +1,5 @@
--TEST--
"extends" tag in a condition
--DEPRECATION--
Since twig/twig 3.27: Using the "extends" tag outside the root of a template is deprecated in index.twig at line 3.
--TEMPLATE--
{% if false %}
{% extends "base.twig" %}
@@ -9,4 +7,5 @@ Since twig/twig 3.27: Using the "extends" tag outside the root of a template is
--TEMPLATE(base.twig)--
--DATA--
return []
--EXPECT--
--EXCEPTION--
Twig\Error\SyntaxError: The "extends" tag can only be used at the root of a template in "index.twig" at line 3.
@@ -1,7 +1,5 @@
--TEST--
"use" tag in a condition
--DEPRECATION--
Since twig/twig 3.27: Using the "use" tag outside the root of a template is deprecated in index.twig at line 3.
--TEMPLATE--
{% if false %}
{% use "base.twig" %}
@@ -9,4 +7,5 @@ Since twig/twig 3.27: Using the "use" tag outside the root of a template is depr
--TEMPLATE(base.twig)--
--DATA--
return []
--EXPECT--
--EXCEPTION--
Twig\Error\SyntaxError: The "use" tag can only be used at the root of a template in "index.twig" at line 3.
@@ -1,7 +1,5 @@
--TEST--
"use" tag in a macro
--DEPRECATION--
Since twig/twig 3.27: Using the "use" tag outside the root of a template is deprecated in index.twig at line 3.
--TEMPLATE--
{% macro input(name, value, type, size) %}
{% use "base.twig" %}
@@ -11,4 +9,5 @@ Since twig/twig 3.27: Using the "use" tag outside the root of a template is depr
--TEMPLATE(base.twig)--
--DATA--
return []
--EXPECT--
--EXCEPTION--
Twig\Error\SyntaxError: The "use" tag can only be used at the root of a template in "index.twig" at line 3.
@@ -1,7 +1,5 @@
--TEST--
"macro" tag in a block
--DEPRECATION--
Since twig/twig 3.27: Using the "macro" tag outside the root of a template is deprecated in index.twig at line 3.
--TEMPLATE--
{% block foo %}
{% macro input(name, value, type, size) %}
@@ -10,4 +8,5 @@ Since twig/twig 3.27: Using the "macro" tag outside the root of a template is de
{% endblock %}
--DATA--
return []
--EXPECT--
--EXCEPTION--
Twig\Error\SyntaxError: The "macro" tag can only be used at the root of a template in "index.twig" at line 3.
@@ -1,7 +1,5 @@
--TEST--
"macro" tag in a condition
--DEPRECATION--
Since twig/twig 3.27: Using the "macro" tag outside the root of a template is deprecated in index.twig at line 3.
--TEMPLATE--
{% if false %}
{% macro input(name, value, type, size) %}
@@ -10,4 +8,5 @@ Since twig/twig 3.27: Using the "macro" tag outside the root of a template is de
{% endif %}
--DATA--
return []
--EXPECT--
--EXCEPTION--
Twig\Error\SyntaxError: The "macro" tag can only be used at the root of a template in "index.twig" at line 3.