From ee81afe6e9c6ba92fd4848f0c36b7b05d387b657 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 2 Jun 2025 16:08:14 +0200 Subject: [PATCH 01/11] Allow Symfony ^8.0 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index e24a315..e3989cd 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": ">=8.2", - "symfony/cache": "^6.4|^7.0", + "symfony/cache": "^6.4|^7.0|^8.0", "symfony/deprecation-contracts": "^2.5|^3", "symfony/service-contracts": "^2.5|^3" }, From ea9f0de0566da5f78471bb781420770591b47bf1 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 2 Jun 2025 17:50:55 +0200 Subject: [PATCH 02/11] Bump Symfony 8 to PHP >= 8.4 --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index e3989cd..e925da6 100644 --- a/composer.json +++ b/composer.json @@ -16,8 +16,8 @@ } ], "require": { - "php": ">=8.2", - "symfony/cache": "^6.4|^7.0|^8.0", + "php": ">=8.4", + "symfony/cache": "^7.4|^8.0", "symfony/deprecation-contracts": "^2.5|^3", "symfony/service-contracts": "^2.5|^3" }, From 8889cca34364b0aa80100fc0437561cae6cfb233 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 4 Jun 2025 18:31:05 +0200 Subject: [PATCH 03/11] Enforce return types on all components --- ExpressionLanguage.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ExpressionLanguage.php b/ExpressionLanguage.php index 379d386..4899537 100644 --- a/ExpressionLanguage.php +++ b/ExpressionLanguage.php @@ -145,10 +145,7 @@ public function registerProvider(ExpressionFunctionProviderInterface $provider): } } - /** - * @return void - */ - protected function registerFunctions() + protected function registerFunctions(): void { $basicPhpFunctions = ['constant', 'min', 'max']; foreach ($basicPhpFunctions as $function) { From 6659bb5afcc3c4a72df58504ac5bc1dcd3a7d974 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sun, 6 Jul 2025 15:40:49 +0200 Subject: [PATCH 04/11] forbid passing null as allowed variables --- CHANGELOG.md | 11 +++++++++++ ExpressionLanguage.php | 11 ++--------- Parser.php | 9 +-------- composer.json | 1 - 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a85455b..b45831f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,17 @@ CHANGELOG ========= +8.0 +--- + + * Remove support for passing `null` as the allowed variable names to `ExpressionLanguage::lint()` and `Parser::lint()`, + pass the `IGNORE_UNKNOWN_VARIABLES` flag instead to ignore unknown variables during linting + + ```diff + -$expressionLanguage->lint($expression, null); + +$expressionLanguage->lint($expression, [], ExpressionLanguage::IGNORE_UNKNOWN_VARIABLES); + ``` + 7.2 --- diff --git a/ExpressionLanguage.php b/ExpressionLanguage.php index 4899537..b9179a7 100644 --- a/ExpressionLanguage.php +++ b/ExpressionLanguage.php @@ -93,20 +93,13 @@ public function parse(Expression|string $expression, array $names, int $flags = /** * Validates the syntax of an expression. * - * @param array|null $names The list of acceptable variable names in the expression + * @param array $names The list of acceptable variable names in the expression * @param int-mask-of $flags * * @throws SyntaxError When the passed expression is invalid */ - public function lint(Expression|string $expression, ?array $names, int $flags = 0): void + public function lint(Expression|string $expression, array $names, int $flags = 0): void { - if (null === $names) { - trigger_deprecation('symfony/expression-language', '7.1', 'Passing "null" as the second argument of "%s()" is deprecated, pass "%s\Parser::IGNORE_UNKNOWN_VARIABLES" instead as a third argument.', __METHOD__, __NAMESPACE__); - - $flags |= Parser::IGNORE_UNKNOWN_VARIABLES; - $names = []; - } - if ($expression instanceof ParsedExpression) { return; } diff --git a/Parser.php b/Parser.php index 32254cd..91b6019 100644 --- a/Parser.php +++ b/Parser.php @@ -113,15 +113,8 @@ public function parse(TokenStream $stream, array $names = [], int $flags = 0): N * * @throws SyntaxError When the passed expression is invalid */ - public function lint(TokenStream $stream, ?array $names = [], int $flags = 0): void + public function lint(TokenStream $stream, array $names = [], int $flags = 0): void { - if (null === $names) { - trigger_deprecation('symfony/expression-language', '7.1', 'Passing "null" as the second argument of "%s()" is deprecated, pass "%s::IGNORE_UNKNOWN_VARIABLES" instead as a third argument.', __METHOD__, __CLASS__); - - $flags |= self::IGNORE_UNKNOWN_VARIABLES; - $names = []; - } - $this->doParse($stream, $names, $flags); } diff --git a/composer.json b/composer.json index e925da6..c468cfc 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,6 @@ "require": { "php": ">=8.4", "symfony/cache": "^7.4|^8.0", - "symfony/deprecation-contracts": "^2.5|^3", "symfony/service-contracts": "^2.5|^3" }, "autoload": { From 96e8888c159f5f672cb39bff7c2463ab187bd9ee Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 24 Jul 2025 14:45:41 +0200 Subject: [PATCH 05/11] Fix typos --- Tests/ParserTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/ParserTest.php b/Tests/ParserTest.php index 0f1c893..8677c03 100644 --- a/Tests/ParserTest.php +++ b/Tests/ParserTest.php @@ -326,7 +326,7 @@ public function testLint($expression, $names, int $checks = 0, ?string $exceptio $parser = new Parser([]); $parser->lint($lexer->tokenize($expression), $names, $checks); - // Parser does't return anything when the correct expression is passed + // Parser doesn't return anything when the correct expression is passed $this->expectNotToPerformAssertions(); } From b3f60d6a9914ac3f88cdf253a42b511ba503ad7b Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Wed, 9 Oct 2024 11:06:51 +0200 Subject: [PATCH 06/11] run tests using PHPUnit 11.5 --- phpunit.xml.dist | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 8e60a89..bf5d7ef 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,10 +1,11 @@ @@ -18,7 +19,7 @@ - + ./ @@ -26,5 +27,9 @@ ./Tests ./vendor - + + + + + From be9035aa4af65cfcad5d31afb4f08f76d8954fc9 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 31 Jul 2025 14:36:46 +0200 Subject: [PATCH 07/11] replace PHPUnit annotations with attributes --- Tests/ExpressionLanguageTest.php | 61 ++++++++--------------------- Tests/LexerTest.php | 5 +-- Tests/Node/AbstractNodeTestCase.php | 13 ++---- Tests/Node/BinaryNodeTest.php | 7 ++-- Tests/ParserTest.php | 13 ++---- 5 files changed, 29 insertions(+), 70 deletions(-) diff --git a/Tests/ExpressionLanguageTest.php b/Tests/ExpressionLanguageTest.php index e8ecfc5..75a25e7 100644 --- a/Tests/ExpressionLanguageTest.php +++ b/Tests/ExpressionLanguageTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\ExpressionLanguage\Tests; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Psr\Cache\CacheItemInterface; use Psr\Cache\CacheItemPoolInterface; @@ -71,9 +72,7 @@ public function testCachedParse() $this->assertSame($savedParsedExpression, $parsedExpression); } - /** - * @dataProvider basicPhpFunctionProvider - */ + #[DataProvider('basicPhpFunctionProvider')] public function testBasicPhpFunction($expression, $expected, $compiled) { $expressionLanguage = new ExpressionLanguage(); @@ -137,9 +136,7 @@ public function testCompiledEnumFunctionWithBackedEnum() $this->assertSame(FooBackedEnum::Bar, $result); } - /** - * @dataProvider providerTestCases - */ + #[DataProvider('providerTestCases')] public function testProviders(iterable $providers) { $expressionLanguage = new ExpressionLanguage(null, $providers); @@ -161,18 +158,14 @@ public static function providerTestCases(): iterable })()]; } - /** - * @dataProvider shortCircuitProviderEvaluate - */ + #[DataProvider('shortCircuitProviderEvaluate')] public function testShortCircuitOperatorsEvaluate($expression, array $values, $expected) { $expressionLanguage = new ExpressionLanguage(); $this->assertSame($expected, $expressionLanguage->evaluate($expression, $values)); } - /** - * @dataProvider shortCircuitProviderCompile - */ + #[DataProvider('shortCircuitProviderCompile')] public function testShortCircuitOperatorsCompile($expression, array $names, $expected) { $result = null; @@ -304,9 +297,7 @@ public function testOperatorCollisions() $this->assertTrue($result); } - /** - * @dataProvider getRegisterCallbacks - */ + #[DataProvider('getRegisterCallbacks')] public function testRegisterAfterParse($registerCallback) { $this->expectException(\LogicException::class); @@ -315,9 +306,7 @@ public function testRegisterAfterParse($registerCallback) $registerCallback($el); } - /** - * @dataProvider getRegisterCallbacks - */ + #[DataProvider('getRegisterCallbacks')] public function testRegisterAfterEval($registerCallback) { $this->expectException(\LogicException::class); @@ -326,18 +315,14 @@ public function testRegisterAfterEval($registerCallback) $registerCallback($el); } - /** - * @dataProvider provideNullSafe - */ + #[DataProvider('provideNullSafe')] public function testNullSafeEvaluate($expression, $foo) { $expressionLanguage = new ExpressionLanguage(); $this->assertNull($expressionLanguage->evaluate($expression, ['foo' => $foo])); } - /** - * @dataProvider provideNullSafe - */ + #[DataProvider('provideNullSafe')] public function testNullSafeCompile($expression, $foo) { $expressionLanguage = new ExpressionLanguage(); @@ -374,9 +359,7 @@ public function bar() yield ['foo?.bar()["baz"]["qux"].quux()', null]; } - /** - * @dataProvider provideInvalidNullSafe - */ + #[DataProvider('provideInvalidNullSafe')] public function testNullSafeEvaluateFails($expression, $foo, $message) { $expressionLanguage = new ExpressionLanguage(); @@ -386,9 +369,7 @@ public function testNullSafeEvaluateFails($expression, $foo, $message) $expressionLanguage->evaluate($expression, ['foo' => $foo]); } - /** - * @dataProvider provideInvalidNullSafe - */ + #[DataProvider('provideInvalidNullSafe')] public function testNullSafeCompileFails($expression, $foo) { $expressionLanguage = new ExpressionLanguage(); @@ -417,18 +398,14 @@ public static function provideInvalidNullSafe() yield ['foo?.bar["baz"].qux.quux', (object) ['bar' => ['baz' => null]], 'Unable to get property "qux" of non-object "foo?.bar["baz"]".']; } - /** - * @dataProvider provideNullCoalescing - */ + #[DataProvider('provideNullCoalescing')] public function testNullCoalescingEvaluate($expression, $foo) { $expressionLanguage = new ExpressionLanguage(); $this->assertSame($expressionLanguage->evaluate($expression, ['foo' => $foo]), 'default'); } - /** - * @dataProvider provideNullCoalescing - */ + #[DataProvider('provideNullCoalescing')] public function testNullCoalescingCompile($expression, $foo) { $expressionLanguage = new ExpressionLanguage(); @@ -459,9 +436,7 @@ public function bar() yield ['foo[123][456][789] ?? "default"', [123 => []]]; } - /** - * @dataProvider getRegisterCallbacks - */ + #[DataProvider('getRegisterCallbacks')] public function testRegisterAfterCompile($registerCallback) { $this->expectException(\LogicException::class); @@ -478,9 +453,7 @@ public static function validCommentProvider() yield ["/* multi\nline */ 'foo'"]; } - /** - * @dataProvider validCommentProvider - */ + #[DataProvider('validCommentProvider')] public function testLintAllowsComments($expression) { $el = new ExpressionLanguage(); @@ -496,9 +469,7 @@ public static function invalidCommentProvider() yield ['1 /* double closing */ */']; } - /** - * @dataProvider invalidCommentProvider - */ + #[DataProvider('invalidCommentProvider')] public function testLintThrowsOnInvalidComments($expression) { $el = new ExpressionLanguage(); diff --git a/Tests/LexerTest.php b/Tests/LexerTest.php index 2827cf6..c05b3a4 100644 --- a/Tests/LexerTest.php +++ b/Tests/LexerTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\ExpressionLanguage\Tests; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Symfony\Component\ExpressionLanguage\Lexer; use Symfony\Component\ExpressionLanguage\SyntaxError; @@ -26,9 +27,7 @@ protected function setUp(): void $this->lexer = new Lexer(); } - /** - * @dataProvider getTokenizeData - */ + #[DataProvider('getTokenizeData')] public function testTokenize($tokens, $expression) { $tokens[] = new Token('end of expression', null, \strlen($expression) + 1); diff --git a/Tests/Node/AbstractNodeTestCase.php b/Tests/Node/AbstractNodeTestCase.php index 7521788..0fc70e7 100644 --- a/Tests/Node/AbstractNodeTestCase.php +++ b/Tests/Node/AbstractNodeTestCase.php @@ -11,14 +11,13 @@ namespace Symfony\Component\ExpressionLanguage\Tests\Node; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Symfony\Component\ExpressionLanguage\Compiler; abstract class AbstractNodeTestCase extends TestCase { - /** - * @dataProvider getEvaluateData - */ + #[DataProvider('getEvaluateData')] public function testEvaluate($expected, $node, $variables = [], $functions = []) { $this->assertSame($expected, $node->evaluate($functions, $variables)); @@ -26,9 +25,7 @@ public function testEvaluate($expected, $node, $variables = [], $functions = []) abstract public static function getEvaluateData(); - /** - * @dataProvider getCompileData - */ + #[DataProvider('getCompileData')] public function testCompile($expected, $node, $functions = []) { $compiler = new Compiler($functions); @@ -38,9 +35,7 @@ public function testCompile($expected, $node, $functions = []) abstract public static function getCompileData(); - /** - * @dataProvider getDumpData - */ + #[DataProvider('getDumpData')] public function testDump($expected, $node) { $this->assertSame($expected, $node->dump()); diff --git a/Tests/Node/BinaryNodeTest.php b/Tests/Node/BinaryNodeTest.php index 375d0a1..592e84d 100644 --- a/Tests/Node/BinaryNodeTest.php +++ b/Tests/Node/BinaryNodeTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\ExpressionLanguage\Tests\Node; +use PHPUnit\Framework\Attributes\TestWith; use Symfony\Component\ExpressionLanguage\Compiler; use Symfony\Component\ExpressionLanguage\Node\ArrayNode; use Symfony\Component\ExpressionLanguage\Node\BinaryNode; @@ -265,10 +266,8 @@ public function testModuloByZero() $node->evaluate([], []); } - /** - * @testWith [1] - * ["true"] - */ + #[TestWith([1])] + #[TestWith(['true'])] public function testInOperatorStrictness(mixed $value) { $array = new ArrayNode(); diff --git a/Tests/ParserTest.php b/Tests/ParserTest.php index 8677c03..aaf9fe6 100644 --- a/Tests/ParserTest.php +++ b/Tests/ParserTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\ExpressionLanguage\Tests; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Symfony\Component\ExpressionLanguage\Lexer; use Symfony\Component\ExpressionLanguage\Node; @@ -59,9 +60,7 @@ public function testParseUnknownFunction() $parser->parse($tokenized); } - /** - * @dataProvider getParseData - */ + #[DataProvider('getParseData')] public function testParse($node, $expression, $names = []) { $lexer = new Lexer(); @@ -269,9 +268,7 @@ private static function createGetAttrNode($node, $item, $type) return new Node\GetAttrNode($node, new Node\ConstantNode($item, Node\GetAttrNode::ARRAY_CALL !== $type), new Node\ArgumentsNode(), $type); } - /** - * @dataProvider getInvalidPostfixData - */ + #[DataProvider('getInvalidPostfixData')] public function testParseWithInvalidPostfixData($expr, $names = []) { $this->expectException(SyntaxError::class); @@ -312,9 +309,7 @@ public function testNameProposal() $parser->parse($lexer->tokenize('foo > bar'), ['foo', 'baz']); } - /** - * @dataProvider getLintData - */ + #[DataProvider('getLintData')] public function testLint($expression, $names, int $checks = 0, ?string $exception = null) { if ($exception) { From 2e92b4ad89bc924d7e991664aed94dd9a602ab93 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 4 Aug 2025 09:53:42 +0200 Subject: [PATCH 08/11] CS fixes --- Tests/Node/ArgumentsNodeTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Tests/Node/ArgumentsNodeTest.php b/Tests/Node/ArgumentsNodeTest.php index 2b25073..d059949 100644 --- a/Tests/Node/ArgumentsNodeTest.php +++ b/Tests/Node/ArgumentsNodeTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\ExpressionLanguage\Tests\Node; use Symfony\Component\ExpressionLanguage\Node\ArgumentsNode; +use Symfony\Component\ExpressionLanguage\Node\ArrayNode; class ArgumentsNodeTest extends ArrayNodeTest { @@ -29,7 +30,7 @@ public static function getDumpData(): \Generator ]; } - protected static function createArrayNode(): \Symfony\Component\ExpressionLanguage\Node\ArrayNode + protected static function createArrayNode(): ArrayNode { return new ArgumentsNode(); } From dc65632e17f1a1dd0feea20d6f20e3dca232e66a Mon Sep 17 00:00:00 2001 From: Dariusz Ruminski Date: Sun, 10 Aug 2025 00:28:14 +0200 Subject: [PATCH 09/11] chore: heredoc indentation as of PHP 7.3 https://www.php.net/manual/en/language.types.string.php#language.types.string.syntax.heredoc --- Tests/Node/NodeTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Tests/Node/NodeTest.php b/Tests/Node/NodeTest.php index 44f8bd7..c6ea41f 100644 --- a/Tests/Node/NodeTest.php +++ b/Tests/Node/NodeTest.php @@ -23,10 +23,10 @@ public function testToString() $node = new Node([new ConstantNode('foo')]); $this->assertEquals(<<<'EOF' -Node( - ConstantNode(value: 'foo') -) -EOF + Node( + ConstantNode(value: 'foo') + ) + EOF , (string) $node); } From b79fe9b0f58b0ea374df0a7d106d6b1e30d1a50d Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 1 Aug 2025 14:58:41 +0200 Subject: [PATCH 10/11] run tests with PHPUnit 12.3 --- Tests/ExpressionLanguageTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/ExpressionLanguageTest.php b/Tests/ExpressionLanguageTest.php index 75a25e7..efd58cf 100644 --- a/Tests/ExpressionLanguageTest.php +++ b/Tests/ExpressionLanguageTest.php @@ -370,7 +370,7 @@ public function testNullSafeEvaluateFails($expression, $foo, $message) } #[DataProvider('provideInvalidNullSafe')] - public function testNullSafeCompileFails($expression, $foo) + public function testNullSafeCompileFails($expression, $foo, $message) { $expressionLanguage = new ExpressionLanguage(); From b53192cdb024d93dd5286110831735a5f3d9ba32 Mon Sep 17 00:00:00 2001 From: Dariusz Ruminski Date: Sun, 10 Aug 2025 00:12:49 +0200 Subject: [PATCH 11/11] chore: PHP CS Fixer - update heredoc handling --- Tests/Node/NodeTest.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Tests/Node/NodeTest.php b/Tests/Node/NodeTest.php index c6ea41f..f8975d4 100644 --- a/Tests/Node/NodeTest.php +++ b/Tests/Node/NodeTest.php @@ -26,8 +26,9 @@ public function testToString() Node( ConstantNode(value: 'foo') ) - EOF - , (string) $node); + EOF, + (string) $node + ); } public function testSerialization()