Skip to content

Commit

Permalink
feature #52230 [Yaml] Allow to get all the enum cases (phansys)
Browse files Browse the repository at this point in the history
This PR was merged into the 7.1 branch.

Discussion
----------

[Yaml] Allow to get all the enum cases

| Q             | A
| ------------- | ---
| Branch?       | 7.1
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Issues        | n/a
| License       | MIT

<!--
Replace this notice by a description of your feature/bugfix.
This will help reviewers and should be a good start for the documentation.

Additionally (see https://symfony.com/releases):
 - Always add tests and ensure they pass.
 - Bug fixes must be submitted against the lowest maintained branch where they apply
   (lowest branches are regularly merged to upper ones so they get the fixes too).
 - Features and deprecations must be submitted against the latest branch.
 - For new features, provide some code snippets to help understand usage.
 - Changelog entry should follow https://symfony.com/doc/current/contributing/code/conventions.html#writing-a-changelog-entry
 - Never break backward compatibility (see https://symfony.com/bc).
-->

With this addition, the `!php/enum` syntax is allowed to expose an array with all the enum cases (the result from [`UnitEnum::cases()`](https://www.php.net/manual/en/unitenum.cases.php)). This is useful for cases like `choices` option from the `Choice` validation constraint:

**BEFORE**:
```yaml
App\Entity\User:
    properties:
        status:
            - Choice:
                choices:
                    - !php/enum 'App\Entity\Enum\UserStatus::Enabled'
                    - !php/enum 'App\Entity\Enum\UserStatus::Disabled'
                    - !php/enum 'App\Entity\Enum\UserStatus::Blocked'
```

**AFTER**:
```yaml
App\Entity\User:
    properties:
        status:
            - Choice:
                choices: !php/enum 'App\Entity\Enum\UserStatus'
```

Prior to the support for enumerations, this was allowed by array constants:

```yaml
App\Entity\User:
    properties:
        status:
            - Choice:
                choices: !php/const 'App\Entity\User::AVAILABLE_STATUSES'
```

Commits
-------

3286539bef [Yaml] Allow Yaml component to get all the enum cases
  • Loading branch information
fabpot committed Feb 3, 2024
2 parents d56caa8 + dd03330 commit 7fc548d
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 13 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
CHANGELOG
=========

7.1
---

* Add support for getting all the enum cases with `!php/enum Foo`

7.0
---

Expand Down
27 changes: 17 additions & 10 deletions Inline.php
Original file line number Diff line number Diff line change
Expand Up @@ -643,24 +643,31 @@ private static function evaluateScalar(string $scalar, int $flags, array &$refer
}

$i = 0;
$enum = self::parseScalar(substr($scalar, 10), 0, null, $i, false);
if ($useValue = str_ends_with($enum, '->value')) {
$enum = substr($enum, 0, -7);
}
if (!\defined($enum)) {
$enumName = self::parseScalar(substr($scalar, 10), 0, null, $i, false);
$useName = str_contains($enumName, '::');
$enum = $useName ? strstr($enumName, '::', true) : $enumName;

if (!enum_exists($enum)) {
throw new ParseException(sprintf('The enum "%s" is not defined.', $enum), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
}
if (!$useName) {
return $enum::cases();
}
if ($useValue = str_ends_with($enumName, '->value')) {
$enumName = substr($enumName, 0, -7);
}

$value = \constant($enum);

if (!$value instanceof \UnitEnum) {
throw new ParseException(sprintf('The string "%s" is not the name of a valid enum.', $enum), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
if (!\defined($enumName)) {
throw new ParseException(sprintf('The string "%s" is not the name of a valid enum.', $enumName), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
}

$value = \constant($enumName);

if (!$useValue) {
return $value;
}
if (!$value instanceof \BackedEnum) {
throw new ParseException(sprintf('The enum "%s" defines no value next to its name.', $enum), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
throw new ParseException(sprintf('The enum "%s" defines no value next to its name.', $enumName), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
}

return $value->value;
Expand Down
18 changes: 15 additions & 3 deletions Tests/InlineTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,21 @@ public function testParsePhpConstantThrowsExceptionWhenUndefined()
public function testParsePhpEnumThrowsExceptionWhenUndefined()
{
$this->expectException(ParseException::class);
$this->expectExceptionMessage('The enum "SomeEnum::Foo" is not defined');
Inline::parse('!php/enum SomeEnum::Foo', Yaml::PARSE_CONSTANT);
$this->expectExceptionMessage('The enum "SomeEnum" is not defined');
Inline::parse('!php/enum SomeEnum', Yaml::PARSE_CONSTANT);
}

public function testParsePhpEnumThrowsExceptionWhenNameUndefined()
{
$this->expectException(ParseException::class);
$this->expectExceptionMessage('The string "Symfony\Component\Yaml\Tests\Fixtures\FooUnitEnum::Foo" is not the name of a valid enum');
Inline::parse('!php/enum Symfony\Component\Yaml\Tests\Fixtures\FooUnitEnum::Foo', Yaml::PARSE_CONSTANT);
}

public function testParsePhpEnumThrowsExceptionWhenNotAnEnum()
{
$this->expectException(ParseException::class);
$this->expectExceptionMessage('The string "PHP_INT_MAX" is not the name of a valid enum');
$this->expectExceptionMessage('The enum "PHP_INT_MAX" is not defined');
Inline::parse('!php/enum PHP_INT_MAX', Yaml::PARSE_CONSTANT);
}

Expand Down Expand Up @@ -718,6 +725,11 @@ public function testDumpUnitEnum()
$this->assertSame("!php/enum Symfony\Component\Yaml\Tests\Fixtures\FooUnitEnum::BAR", Inline::dump(FooUnitEnum::BAR));
}

public function testParseUnitEnumCases()
{
$this->assertSame(FooUnitEnum::cases(), Inline::parse("!php/enum Symfony\Component\Yaml\Tests\Fixtures\FooUnitEnum", Yaml::PARSE_CONSTANT));
}

public function testParseUnitEnum()
{
$this->assertSame(FooUnitEnum::BAR, Inline::parse("!php/enum Symfony\Component\Yaml\Tests\Fixtures\FooUnitEnum::BAR", Yaml::PARSE_CONSTANT));
Expand Down

0 comments on commit 7fc548d

Please sign in to comment.