From 53bfee4440bdd65d52216ebdbec16132221050c1 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Thu, 15 Dec 2022 20:28:50 +0100 Subject: [PATCH] [ExpressionLanguage] Add `enum` expression function --- .../Component/ExpressionLanguage/CHANGELOG.md | 5 ++ .../ExpressionLanguage/ExpressionLanguage.php | 13 +++++ .../Tests/ExpressionLanguageTest.php | 49 +++++++++++++++++++ .../Tests/Fixtures/FooBackedEnum.php | 8 +++ .../Tests/Fixtures/FooEnum.php | 8 +++ 5 files changed, 83 insertions(+) create mode 100644 src/Symfony/Component/ExpressionLanguage/Tests/Fixtures/FooBackedEnum.php create mode 100644 src/Symfony/Component/ExpressionLanguage/Tests/Fixtures/FooEnum.php diff --git a/src/Symfony/Component/ExpressionLanguage/CHANGELOG.md b/src/Symfony/Component/ExpressionLanguage/CHANGELOG.md index 9210fc4cc33fb..44a3478ff51b4 100644 --- a/src/Symfony/Component/ExpressionLanguage/CHANGELOG.md +++ b/src/Symfony/Component/ExpressionLanguage/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +6.3 +--- + + * Add `enum` expression function + 6.2 --- diff --git a/src/Symfony/Component/ExpressionLanguage/ExpressionLanguage.php b/src/Symfony/Component/ExpressionLanguage/ExpressionLanguage.php index e076eb9bc56e0..ed233cd270c5a 100644 --- a/src/Symfony/Component/ExpressionLanguage/ExpressionLanguage.php +++ b/src/Symfony/Component/ExpressionLanguage/ExpressionLanguage.php @@ -138,6 +138,19 @@ public function registerProvider(ExpressionFunctionProviderInterface $provider) protected function registerFunctions() { $this->addFunction(ExpressionFunction::fromPhp('constant')); + + $this->addFunction(new ExpressionFunction('enum', + static fn ($str): string => sprintf("(\constant(\$v = (%s))) instanceof \UnitEnum ? \constant(\$v) : throw new \TypeError(\sprintf('The string \"%%s\" is not the name of a valid enum case.', \$v))", $str), + static function ($arguments, $str): \UnitEnum { + $value = \constant($str); + + if (!$value instanceof \UnitEnum) { + throw new \TypeError(sprintf('The string "%s" is not the name of a valid enum case.', $str)); + } + + return $value; + } + )); } private function getLexer(): Lexer diff --git a/src/Symfony/Component/ExpressionLanguage/Tests/ExpressionLanguageTest.php b/src/Symfony/Component/ExpressionLanguage/Tests/ExpressionLanguageTest.php index 2efa7a3be4722..98a91600d6612 100644 --- a/src/Symfony/Component/ExpressionLanguage/Tests/ExpressionLanguageTest.php +++ b/src/Symfony/Component/ExpressionLanguage/Tests/ExpressionLanguageTest.php @@ -18,6 +18,8 @@ use Symfony\Component\ExpressionLanguage\ExpressionLanguage; use Symfony\Component\ExpressionLanguage\ParsedExpression; use Symfony\Component\ExpressionLanguage\SyntaxError; +use Symfony\Component\ExpressionLanguage\Tests\Fixtures\FooBackedEnum; +use Symfony\Component\ExpressionLanguage\Tests\Fixtures\FooEnum; use Symfony\Component\ExpressionLanguage\Tests\Fixtures\TestProvider; class ExpressionLanguageTest extends TestCase @@ -78,6 +80,53 @@ public function testConstantFunction() $this->assertEquals('\constant("PHP_VERSION")', $expressionLanguage->compile('constant("PHP_VERSION")')); } + public function testEnumFunctionWithConstantThrows() + { + $this->expectException(\TypeError::class); + $this->expectExceptionMessage('The string "PHP_VERSION" is not the name of a valid enum case.'); + $expressionLanguage = new ExpressionLanguage(); + $expressionLanguage->evaluate('enum("PHP_VERSION")'); + } + + public function testCompiledEnumFunctionWithConstantThrows() + { + $this->expectException(\TypeError::class); + $this->expectExceptionMessage('The string "PHP_VERSION" is not the name of a valid enum case.'); + $expressionLanguage = new ExpressionLanguage(); + eval($expressionLanguage->compile('enum("PHP_VERSION")').';'); + } + + public function testEnumFunction() + { + $expressionLanguage = new ExpressionLanguage(); + $this->assertSame(FooEnum::Foo, $expressionLanguage->evaluate('enum("Symfony\\\\Component\\\\ExpressionLanguage\\\\Tests\\\\Fixtures\\\\FooEnum::Foo")')); + } + + public function testCompiledEnumFunction() + { + $result = null; + $expressionLanguage = new ExpressionLanguage(); + eval(sprintf('$result = %s;', $expressionLanguage->compile('enum("Symfony\\\\Component\\\\ExpressionLanguage\\\\Tests\\\\Fixtures\\\\FooEnum::Foo")'))); + + $this->assertSame(FooEnum::Foo, $result); + } + + public function testBackedEnumFunction() + { + $expressionLanguage = new ExpressionLanguage(); + $this->assertSame(FooBackedEnum::Bar, $expressionLanguage->evaluate('enum("Symfony\\\\Component\\\\ExpressionLanguage\\\\Tests\\\\Fixtures\\\\FooBackedEnum::Bar")')); + $this->assertSame('Foo', $expressionLanguage->evaluate('enum("Symfony\\\\Component\\\\ExpressionLanguage\\\\Tests\\\\Fixtures\\\\FooBackedEnum::Bar").value')); + } + + public function testCompiledEnumFunctionWithBackedEnum() + { + $result = null; + $expressionLanguage = new ExpressionLanguage(); + eval(sprintf('$result = %s;', $expressionLanguage->compile('enum("Symfony\\\\Component\\\\ExpressionLanguage\\\\Tests\\\\Fixtures\\\\FooBackedEnum::Bar")'))); + + $this->assertSame(FooBackedEnum::Bar, $result); + } + public function testProviders() { $expressionLanguage = new ExpressionLanguage(null, [new TestProvider()]); diff --git a/src/Symfony/Component/ExpressionLanguage/Tests/Fixtures/FooBackedEnum.php b/src/Symfony/Component/ExpressionLanguage/Tests/Fixtures/FooBackedEnum.php new file mode 100644 index 0000000000000..8bf81231b4dac --- /dev/null +++ b/src/Symfony/Component/ExpressionLanguage/Tests/Fixtures/FooBackedEnum.php @@ -0,0 +1,8 @@ +