From 3794efe66210873ea4598aa3a276b8f5a795fec3 Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Sun, 9 Feb 2025 14:48:10 +0100 Subject: [PATCH] Fix support for ignoring syntax erros in an undefined handler in guard --- src/ExpressionParser.php | 23 ++++++++++++++-- .../Fixtures/tags/guard/throwing_handler.test | 22 +++++++++++++++ tests/IntegrationTest.php | 27 +++++++++++++++++++ 3 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 tests/Fixtures/tags/guard/throwing_handler.test diff --git a/src/ExpressionParser.php b/src/ExpressionParser.php index d82e9c0e79a..233139ee4ab 100644 --- a/src/ExpressionParser.php +++ b/src/ExpressionParser.php @@ -799,7 +799,17 @@ private function getTest(int $line): TwigTest private function getFunction(string $name, int $line): TwigFunction { - if (!$function = $this->env->getFunction($name)) { + try { + $function = $this->env->getFunction($name); + } catch (SyntaxError $e) { + if (!$this->parser->shouldIgnoreUnknownTwigCallables()) { + throw $e; + } + + $function = null; + } + + if (!$function) { if ($this->parser->shouldIgnoreUnknownTwigCallables()) { return new TwigFunction($name, fn () => ''); } @@ -819,7 +829,16 @@ private function getFunction(string $name, int $line): TwigFunction private function getFilter(string $name, int $line): TwigFilter { - if (!$filter = $this->env->getFilter($name)) { + try { + $filter = $this->env->getFilter($name); + } catch (SyntaxError $e) { + if (!$this->parser->shouldIgnoreUnknownTwigCallables()) { + throw $e; + } + + $filter = null; + } + if (!$filter) { if ($this->parser->shouldIgnoreUnknownTwigCallables()) { return new TwigFilter($name, fn () => ''); } diff --git a/tests/Fixtures/tags/guard/throwing_handler.test b/tests/Fixtures/tags/guard/throwing_handler.test new file mode 100644 index 00000000000..37e32ef6c00 --- /dev/null +++ b/tests/Fixtures/tags/guard/throwing_handler.test @@ -0,0 +1,22 @@ +--TEST-- +"guard" creates a compilation time condition on Twig callables availability +--TEMPLATE-- +{% guard filter throwing_undefined_filter %} + NEVER + {{ 'a'|throwing_undefined_filter }} +{% else -%} + The throwing_undefined_filter filter doesn't exist +{% endguard %} + +{% guard function throwing_undefined_function -%} + NEVER + {{ throwing_undefined_function() }} +{% else -%} + The throwing_undefined_function function doesn't exist +{% endguard %} +--DATA-- +return [] +--EXPECT-- +The throwing_undefined_filter filter doesn't exist + +The throwing_undefined_function function doesn't exist diff --git a/tests/IntegrationTest.php b/tests/IntegrationTest.php index f4889cd754b..273324d1061 100644 --- a/tests/IntegrationTest.php +++ b/tests/IntegrationTest.php @@ -12,6 +12,7 @@ */ use Twig\DeprecatedCallableInfo; +use Twig\Error\SyntaxError; use Twig\Extension\AbstractExtension; use Twig\Extension\DebugExtension; use Twig\Extension\SandboxExtension; @@ -49,6 +50,32 @@ public function getExtensions() ]; } + protected function getUndefinedFunctionCallbacks(): array + { + return [ + static function (string $name) { + if ('throwing_undefined_function' === $name) { + throw new SyntaxError('This function is undefined in the tests.'); + } + + return false; + }, + ]; + } + + protected function getUndefinedTokenParserCallbacks(): array + { + return [ + static function (string $name) { + if ('throwing_undefined_filter' === $name) { + throw new SyntaxError('This filter is undefined in the tests.'); + } + + return false; + }, + ]; + } + protected static function getFixturesDirectory(): string { return __DIR__.'/Fixtures/';