diff --git a/extra/html-extra/HtmlExtension.php b/extra/html-extra/HtmlExtension.php index dcee84f52a..7776f615ff 100644 --- a/extra/html-extra/HtmlExtension.php +++ b/extra/html-extra/HtmlExtension.php @@ -108,6 +108,6 @@ public static function htmlClasses(...$args): string } } - return implode(' ', array_unique($classes)); + return implode(' ', array_unique(array_filter($classes, static function($v) { return '' !== $v; }))); } } diff --git a/extra/html-extra/Tests/Fixtures/html_classes.test b/extra/html-extra/Tests/Fixtures/html_classes.test index 8a5304cf63..65ecaba6ad 100644 --- a/extra/html-extra/Tests/Fixtures/html_classes.test +++ b/extra/html-extra/Tests/Fixtures/html_classes.test @@ -1,12 +1,12 @@ --TEST-- "html_classes" function --TEMPLATE-- -{{ html_classes('a', {'b': true, 'c': false}, 'd') }} +{{ html_classes('a', {'b': true, 'c': false}, 'd', false ? 'e', true ? 'f', '0') }} {% set class_a = 'a' %} {% set class_b = 'b' %} {{ html_classes(class_a, {(class_b): true})}} --DATA-- return [] --EXPECT-- -a b d +a b d f 0 a b diff --git a/src/Extension/CoreExtension.php b/src/Extension/CoreExtension.php index 8c384e197f..b3429dd624 100644 --- a/src/Extension/CoreExtension.php +++ b/src/Extension/CoreExtension.php @@ -329,7 +329,7 @@ public static function cycle($values, $position) } if (!\count($values)) { - throw new RuntimeError('The "cycle" function does not work on empty arrays'); + throw new RuntimeError('The "cycle" function does not work on empty arrays.'); } return $values[$position % \count($values)]; @@ -476,7 +476,7 @@ public static function sprintf($format, ...$values) * * @internal */ - public static function dateConverter(Environment $env, $date = null, $timezone = null): \DateTimeImmutable + public static function dateConverter(Environment $env, $date = null, $timezone = null): \DateTime|\DateTimeImmutable { // determine the timezone if (false !== $timezone) { @@ -492,7 +492,7 @@ public static function dateConverter(Environment $env, $date = null, $timezone = return false !== $timezone ? $date->setTimezone($timezone) : $date; } - if ($date instanceof \DateTimeInterface) { + if ($date instanceof \DateTime) { $date = \DateTimeImmutable::createFromInterface($date); if (false !== $timezone) { return $date->setTimezone($timezone); diff --git a/src/Node/CheckSecurityNode.php b/src/Node/CheckSecurityNode.php index 9df4ca913d..2b131ce6b1 100644 --- a/src/Node/CheckSecurityNode.php +++ b/src/Node/CheckSecurityNode.php @@ -24,6 +24,11 @@ class CheckSecurityNode extends Node private array $usedTags; private array $usedFunctions; + /** + * @param array $usedFilters + * @param array $usedTags + * @param array $usedFunctions + */ public function __construct(array $usedFilters, array $usedTags, array $usedFunctions) { $this->usedFilters = $usedFilters; @@ -35,32 +40,21 @@ public function __construct(array $usedFilters, array $usedTags, array $usedFunc public function compile(Compiler $compiler): void { - $tags = $filters = $functions = []; - foreach (['tags', 'filters', 'functions'] as $type) { - foreach ($this->{'used'.ucfirst($type)} as $name => $node) { - if ($node instanceof Node) { - ${$type}[$name] = $node->getTemplateLine(); - } else { - ${$type}[$node] = null; - } - } - } - $compiler ->write("\n") ->write("public function checkSecurity()\n") ->write("{\n") ->indent() - ->write('static $tags = ')->repr(array_filter($tags))->raw(";\n") - ->write('static $filters = ')->repr(array_filter($filters))->raw(";\n") - ->write('static $functions = ')->repr(array_filter($functions))->raw(";\n\n") + ->write('static $tags = ')->repr(array_filter($this->usedTags))->raw(";\n") + ->write('static $filters = ')->repr(array_filter($this->usedFilters))->raw(";\n") + ->write('static $functions = ')->repr(array_filter($this->usedFunctions))->raw(";\n\n") ->write("try {\n") ->indent() ->write("\$this->sandbox->checkSecurity(\n") ->indent() - ->write(!$tags ? "[],\n" : "['".implode("', '", array_keys($tags))."'],\n") - ->write(!$filters ? "[],\n" : "['".implode("', '", array_keys($filters))."'],\n") - ->write(!$functions ? "[],\n" : "['".implode("', '", array_keys($functions))."'],\n") + ->write(!$this->usedTags ? "[],\n" : "['".implode("', '", array_keys($this->usedTags))."'],\n") + ->write(!$this->usedFilters ? "[],\n" : "['".implode("', '", array_keys($this->usedFilters))."'],\n") + ->write(!$this->usedFunctions ? "[],\n" : "['".implode("', '", array_keys($this->usedFunctions))."'],\n") ->write("\$this->source\n") ->outdent() ->write(");\n") diff --git a/src/NodeVisitor/SandboxNodeVisitor.php b/src/NodeVisitor/SandboxNodeVisitor.php index 04431168c2..1933fa42be 100644 --- a/src/NodeVisitor/SandboxNodeVisitor.php +++ b/src/NodeVisitor/SandboxNodeVisitor.php @@ -34,8 +34,11 @@ final class SandboxNodeVisitor implements NodeVisitorInterface { private bool $inAModule = false; + /** @var array */ private array $tags; + /** @var array */ private array $filters; + /** @var array */ private array $functions; private bool $needsToStringWrap = false; @@ -51,22 +54,22 @@ public function enterNode(Node $node, Environment $env): Node } elseif ($this->inAModule) { // look for tags if ($node->getNodeTag() && !isset($this->tags[$node->getNodeTag()])) { - $this->tags[$node->getNodeTag()] = $node; + $this->tags[$node->getNodeTag()] = $node->getTemplateLine(); } // look for filters if ($node instanceof FilterExpression && !isset($this->filters[$node->getNode('filter')->getAttribute('value')])) { - $this->filters[$node->getNode('filter')->getAttribute('value')] = $node; + $this->filters[$node->getNode('filter')->getAttribute('value')] = $node->getTemplateLine(); } // look for functions if ($node instanceof FunctionExpression && !isset($this->functions[$node->getAttribute('name')])) { - $this->functions[$node->getAttribute('name')] = $node; + $this->functions[$node->getAttribute('name')] = $node->getTemplateLine(); } // the .. operator is equivalent to the range() function if ($node instanceof RangeBinary && !isset($this->functions['range'])) { - $this->functions['range'] = $node; + $this->functions['range'] = $node->getTemplateLine(); } if ($node instanceof PrintNode) { diff --git a/src/Test/IntegrationTestCase.php b/src/Test/IntegrationTestCase.php index 0323e5a828..f3ee733866 100644 --- a/src/Test/IntegrationTestCase.php +++ b/src/Test/IntegrationTestCase.php @@ -189,7 +189,7 @@ protected function doIntegrationTest($file, $message, $condition, $templates, $e // avoid using the same PHP class name for different cases $p = new \ReflectionProperty($twig, 'templateClassPrefix'); $p->setAccessible(true); - $p->setValue($twig, '__TwigTemplate_'.hash('xxh128', uniqid(mt_rand(), true), false).'_'); + $p->setValue($twig, '__TwigTemplate_'.hash('xxh128', uniqid((string) mt_rand(), true), false).'_'); $deprecations = []; try { diff --git a/tests/Extension/EscaperTest.php b/tests/Extension/EscaperTest.php index c465789153..d8fedc64e2 100644 --- a/tests/Extension/EscaperTest.php +++ b/tests/Extension/EscaperTest.php @@ -17,7 +17,7 @@ use Twig\Extension\EscaperExtension; use Twig\Loader\LoaderInterface; -class Twig_Tests_Extension_EscaperTest extends TestCase +class EscaperTest extends TestCase { /** * All character encodings supported by htmlspecialchars(). diff --git a/tests/Fixtures/functions/cycle_empty.test b/tests/Fixtures/functions/cycle_empty.test index 1eaffc8e5f..bb338452a6 100644 --- a/tests/Fixtures/functions/cycle_empty.test +++ b/tests/Fixtures/functions/cycle_empty.test @@ -5,4 +5,4 @@ --DATA-- return [] --EXCEPTION-- -Twig\Error\RuntimeError: The "cycle" function does not work on empty arrays in "index.twig" at line 2 +Twig\Error\RuntimeError: The "cycle" function does not work on empty arrays in "index.twig" at line 2. diff --git a/tests/Fixtures/functions/include/template_instance.test b/tests/Fixtures/functions/include/template_instance.test index 4c8b450835..be18d244ac 100644 --- a/tests/Fixtures/functions/include/template_instance.test +++ b/tests/Fixtures/functions/include/template_instance.test @@ -1,5 +1,5 @@ --TEST-- -"include" function accepts Twig_Template instance +"include" function accepts Twig\Template instance --TEMPLATE-- {{ include(foo) }} FOO --TEMPLATE(foo.twig)-- diff --git a/tests/Fixtures/tags/inheritance/parent_as_template_wrapper.test b/tests/Fixtures/tags/inheritance/parent_as_template_wrapper.test index 1aaed556c5..cf257f25dc 100644 --- a/tests/Fixtures/tags/inheritance/parent_as_template_wrapper.test +++ b/tests/Fixtures/tags/inheritance/parent_as_template_wrapper.test @@ -1,5 +1,5 @@ --TEST-- -"extends" tag with a parent as a Twig_TemplateWrapper instance +"extends" tag with a parent as a Twig\TemplateWrapper instance --TEMPLATE-- {% extends foo %} diff --git a/tests/Fixtures/tags/inheritance/template_instance.test b/tests/Fixtures/tags/inheritance/template_instance.test index a5a223886d..b9009e5df5 100644 --- a/tests/Fixtures/tags/inheritance/template_instance.test +++ b/tests/Fixtures/tags/inheritance/template_instance.test @@ -1,5 +1,5 @@ --TEST-- -"extends" tag accepts Twig_Template instance +"extends" tag accepts Twig\Template instance --TEMPLATE-- {% extends foo %} diff --git a/tests/Node/Expression/CallTest.php b/tests/Node/Expression/CallTest.php index 992eacfcef..72681a4a1f 100644 --- a/tests/Node/Expression/CallTest.php +++ b/tests/Node/Expression/CallTest.php @@ -112,10 +112,10 @@ public function customFunctionWithArbitraryArguments() public function testResolveArgumentsWithMissingParameterForArbitraryArgumentsOnFunction() { $this->expectException(\LogicException::class); - $this->expectExceptionMessageMatches('#^The last parameter of "Twig\\\\Tests\\\\Node\\\\Expression\\\\custom_Twig_Tests_Node_Expression_CallTest_function" for function "foo" must be an array with default value, eg\\. "array \\$arg \\= \\[\\]"\\.$#'); + $this->expectExceptionMessageMatches('#^The last parameter of "Twig\\\\Tests\\\\Node\\\\Expression\\\\custom_call_test_function" for function "foo" must be an array with default value, eg\\. "array \\$arg \\= \\[\\]"\\.$#'); $node = new Node_Expression_Call([], ['type' => 'function', 'name' => 'foo', 'is_variadic' => true]); - $node->getArguments('Twig\Tests\Node\Expression\custom_Twig_Tests_Node_Expression_CallTest_function', []); + $node->getArguments('Twig\Tests\Node\Expression\custom_call_test_function', []); } public function testResolveArgumentsWithMissingParameterForArbitraryArgumentsOnObject() @@ -143,6 +143,6 @@ public function __invoke($required) } } -function custom_Twig_Tests_Node_Expression_CallTest_function($required) +function custom_call_test_function($required) { } diff --git a/tests/Util/DeprecationCollectorTest.php b/tests/Util/DeprecationCollectorTest.php index 7b5794d83c..18f889f6a4 100644 --- a/tests/Util/DeprecationCollectorTest.php +++ b/tests/Util/DeprecationCollectorTest.php @@ -28,7 +28,7 @@ public function testCollect() $twig->addFunction(new TwigFunction('deprec', [$this, 'deprec'], ['deprecated' => '1.1'])); $collector = new DeprecationCollector($twig); - $deprecations = $collector->collect(new Twig_Tests_Util_Iterator()); + $deprecations = $collector->collect(new Iterator()); $this->assertEquals(['Twig Function "deprec" is deprecated since version 1.1 in deprec.twig at line 1.'], $deprecations); } @@ -38,7 +38,7 @@ public function deprec() } } -class Twig_Tests_Util_Iterator implements \IteratorAggregate +class Iterator implements \IteratorAggregate { public function getIterator(): \Traversable {