Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitf1daab5

Browse files
[Config] Allow using an enum FQCN withEnumNode
1 parent74df71a commitf1daab5

File tree

12 files changed

+166
-8
lines changed

12 files changed

+166
-8
lines changed

‎src/Symfony/Component/Config/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ CHANGELOG
55
---
66

77
* Add`#[WhenNot]` attribute to prevent service from being registered in a specific environment
8+
* Allow using an enum FQCN with`EnumNode`
89

910
7.1
1011
---

‎src/Symfony/Component/Config/Definition/Builder/EnumNodeDefinition.php

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
class EnumNodeDefinitionextends ScalarNodeDefinition
2222
{
2323
privatearray$values;
24+
privatestring$enumFqcn;
2425

2526
/**
2627
* @return $this
@@ -36,17 +37,28 @@ public function values(array $values): static
3637
return$this;
3738
}
3839

40+
publicfunctionenumFqcn(string$enumFqcn):static
41+
{
42+
if (!enum_exists($enumFqcn)) {
43+
thrownew \InvalidArgumentException(sprintf('The enum class "%s" does not exist.',$enumFqcn));
44+
}
45+
46+
$this->enumFqcn =$enumFqcn;
47+
48+
return$this;
49+
}
50+
3951
/**
4052
* Instantiate a Node.
4153
*
4254
* @throws \RuntimeException
4355
*/
4456
protectedfunctioninstantiateNode():EnumNode
4557
{
46-
if (!isset($this->values)) {
47-
thrownew \RuntimeException('You must call ->values() on enum nodes.');
58+
if (!isset($this->values) && !isset($this->enumFqcn)) {
59+
thrownew \RuntimeException('You must calleither->values() or ->enumFqcn() on enum nodes.');
4860
}
4961

50-
returnnewEnumNode($this->name,$this->parent,$this->values,$this->pathSeparator);
62+
returnnewEnumNode($this->name,$this->parent,$this->values ?? [$this->enumFqcn],$this->pathSeparator);
5163
}
5264
}

‎src/Symfony/Component/Config/Definition/EnumNode.php

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,19 @@
2121
class EnumNodeextends ScalarNode
2222
{
2323
privatearray$values;
24+
private ?string$enumFqcn =null;
2425

2526
publicfunction__construct(?string$name, ?NodeInterface$parent =null,array$values = [],string$pathSeparator = BaseNode::DEFAULT_PATH_SEPARATOR)
2627
{
2728
if (!$values) {
2829
thrownew \InvalidArgumentException('$values must contain at least one element.');
2930
}
3031

32+
if (1 ===\count($values) &&\is_string($values[0]) &&\enum_exists($enumFqcn =$values[0]) &&\is_a($enumFqcn, \BackedEnum::class,true)) {
33+
$values =$enumFqcn::cases();
34+
$this->enumFqcn =$enumFqcn;
35+
}
36+
3137
foreach ($valuesas$value) {
3238
if (null ===$value ||\is_scalar($value)) {
3339
continue;
@@ -56,6 +62,10 @@ public function getValues(): array
5662
*/
5763
publicfunctiongetPermissibleValues(string$separator):string
5864
{
65+
if ($this->enumFqcn) {
66+
returnimplode($separator,array_map(staticfn (\BackedEnum$case) =>$case->value,$this->enumFqcn::cases()));
67+
}
68+
5969
returnimplode($separator,array_unique(array_map(staticfunction (mixed$value):string {
6070
if (!$valueinstanceof \UnitEnum) {
6171
returnjson_encode($value);
@@ -78,13 +88,37 @@ protected function finalizeValue(mixed $value): mixed
7888
{
7989
$value =parent::finalizeValue($value);
8090

81-
if (!\in_array($value,$this->values,true)) {
82-
$ex =newInvalidConfigurationException(\sprintf('The value %s is not allowed for path "%s". Permissible values: %s',json_encode($value),$this->getPath(),$this->getPermissibleValues(',')));
83-
$ex->setPath($this->getPath());
91+
if ($this->enumFqcn) {
92+
if (\is_a($value,$this->enumFqcn,true)) {
93+
return$value;
94+
}
95+
96+
if ($valueinstanceof \UnitEnum) {
97+
thrownewInvalidConfigurationException(sprintf('The value should be part of the "%s" enum, got a value from the "%s" enum.',$this->enumFqcn,$value::class));
98+
}
8499

85-
throw$ex;
100+
if (\is_string($value) ||\is_int($value)) {
101+
$case =$this->enumFqcn::tryFrom($value);
102+
if (null !==$case) {
103+
return$case;
104+
}
105+
}
106+
107+
throw$this->createInvalidValueException($value);
108+
}
109+
110+
if (!\in_array($value,$this->values,true)) {
111+
throw$this->createInvalidValueException($value);
86112
}
87113

88114
return$value;
89115
}
116+
117+
privatefunctioncreateInvalidValueException(mixed$value):InvalidConfigurationException
118+
{
119+
$ex =newInvalidConfigurationException(\sprintf('The value %s is not allowed for path "%s". Permissible values: %s',json_encode($value),$this->getPath(),$this->getPermissibleValues(',')));
120+
$ex->setPath($this->getPath());
121+
122+
return$ex;
123+
}
90124
}

‎src/Symfony/Component/Config/Tests/Builder/Fixtures/PrimitiveTypes.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
useSymfony\Component\Config\Definition\Builder\TreeBuilder;
1515
useSymfony\Component\Config\Definition\ConfigurationInterface;
16+
useSymfony\Component\Config\Tests\Fixtures\BackedTestEnum;
1617
useSymfony\Component\Config\Tests\Fixtures\TestEnum;
1718

1819
class PrimitiveTypesimplements ConfigurationInterface
@@ -25,6 +26,7 @@ public function getConfigTreeBuilder(): TreeBuilder
2526
->children()
2627
->booleanNode('boolean_node')->end()
2728
->enumNode('enum_node')->values(['foo','bar','baz', TestEnum::Bar])->end()
29+
->enumNode('fqcn_enum_node')->enumFqcn(BackedTestEnum::class)->end()
2830
->floatNode('float_node')->end()
2931
->integerNode('integer_node')->end()
3032
->scalarNode('scalar_node')->end()

‎src/Symfony/Component/Config/Tests/Builder/Fixtures/PrimitiveTypes/Symfony/Config/PrimitiveTypesConfig.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ class PrimitiveTypesConfig implements \Symfony\Component\Config\Builder\ConfigBu
1212
{
1313
private$booleanNode;
1414
private$enumNode;
15+
private$fqcnEnumNode;
1516
private$floatNode;
1617
private$integerNode;
1718
private$scalarNode;
@@ -44,6 +45,19 @@ public function enumNode($value): static
4445
return$this;
4546
}
4647

48+
/**
49+
* @default null
50+
* @param ParamConfigurator|\Symfony\Component\Config\Tests\Fixtures\BackedTestEnum::Foo|\Symfony\Component\Config\Tests\Fixtures\BackedTestEnum::Bar $value
51+
* @return $this
52+
*/
53+
publicfunctionfqcnEnumNode($value):static
54+
{
55+
$this->_usedProperties['fqcnEnumNode'] =true;
56+
$this->fqcnEnumNode =$value;
57+
58+
return$this;
59+
}
60+
4761
/**
4862
* @default null
4963
* @param ParamConfigurator|float $value
@@ -115,6 +129,12 @@ public function __construct(array $value = [])
115129
unset($value['enum_node']);
116130
}
117131

132+
if (array_key_exists('fqcn_enum_node',$value)) {
133+
$this->_usedProperties['fqcnEnumNode'] =true;
134+
$this->fqcnEnumNode =$value['fqcn_enum_node'];
135+
unset($value['fqcn_enum_node']);
136+
}
137+
118138
if (array_key_exists('float_node',$value)) {
119139
$this->_usedProperties['floatNode'] =true;
120140
$this->floatNode =$value['float_node'];
@@ -153,6 +173,9 @@ public function toArray(): array
153173
if (isset($this->_usedProperties['enumNode'])) {
154174
$output['enum_node'] =$this->enumNode;
155175
}
176+
if (isset($this->_usedProperties['fqcnEnumNode'])) {
177+
$output['fqcn_enum_node'] =$this->fqcnEnumNode;
178+
}
156179
if (isset($this->_usedProperties['floatNode'])) {
157180
$output['float_node'] =$this->floatNode;
158181
}

‎src/Symfony/Component/Config/Tests/Definition/Builder/EnumNodeDefinitionTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public function testWithOneValue()
2828
publicfunctiontestNoValuesPassed()
2929
{
3030
$this->expectException(\RuntimeException::class);
31-
$this->expectExceptionMessage('You must call ->values() on enum nodes.');
31+
$this->expectExceptionMessage('You must calleither->values() or ->enumFqcn() on enum nodes.');
3232
$def =newEnumNodeDefinition('foo');
3333
$def->getNode();
3434
}

‎src/Symfony/Component/Config/Tests/Definition/Dumper/XmlReferenceDumperTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ private function getConfigurationAsString()
4242
<!-- scalar-deprecated-with-message: Deprecated (Since vendor/package 1.1: Deprecation custom message for "scalar_deprecated_with_message" at "acme_root") -->
4343
<!-- enum-with-default: One of "this"; "that" -->
4444
<!-- enum: One of "this"; "that"; Symfony\Component\Config\Tests\Fixtures\TestEnum::Ccc -->
45+
<!-- enum-with-class: One of foo; bar -->
4546
<!-- variable: Example: foo, bar -->
4647
<config
4748
boolean="true"
@@ -58,6 +59,7 @@ private function getConfigurationAsString()
5859
node-with-a-looong-name=""
5960
enum-with-default="this"
6061
enum=""
62+
enum-with-class=""
6163
variable=""
6264
custom-node="true"
6365
>

‎src/Symfony/Component/Config/Tests/Definition/Dumper/YamlReferenceDumperTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ private function getConfigurationAsString(): string
103103
node_with_a_looong_name: ~
104104
enum_with_default: this # One of "this"; "that"
105105
enum: ~ # One of "this"; "that"; Symfony\Component\Config\Tests\Fixtures\TestEnum::Ccc
106+
enum_with_class: ~ # One of foo; bar
106107
107108
# some info
108109
array:

‎src/Symfony/Component/Config/Tests/Definition/EnumNodeTest.php

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
usePHPUnit\Framework\TestCase;
1515
useSymfony\Component\Config\Definition\EnumNode;
1616
useSymfony\Component\Config\Definition\Exception\InvalidConfigurationException;
17+
useSymfony\Component\Config\Tests\Fixtures\BackedTestEnum;
18+
useSymfony\Component\Config\Tests\Fixtures\BackedTestEnum2;
1719
useSymfony\Component\Config\Tests\Fixtures\TestEnum;
1820
useSymfony\Component\Config\Tests\Fixtures\TestEnum2;
1921

@@ -61,6 +63,67 @@ public function testFinalizeWithInvalidValue()
6163
$node->finalize('foobar');
6264
}
6365

66+
publicfunctiontestFinalizeWithOnlyUnitEnumFqcnDoesntDoAnythingSpecial()
67+
{
68+
$node =newEnumNode('foo',null, [TestEnum::class]);
69+
70+
$this->expectException(InvalidConfigurationException::class);
71+
$this->expectExceptionMessage('The value "foobar" is not allowed for path "foo". Permissible values: "Symfony\\\\Component\\\\Config\\\\Tests\\\\Fixtures\\\\TestEnum"');
72+
73+
$node->finalize('foobar');
74+
}
75+
76+
publicfunctiontestFinalizeWithEnumFqcn()
77+
{
78+
$node =newEnumNode('foo',null, [BackedTestEnum::class]);
79+
80+
$this->assertSame(BackedTestEnum::Foo,$node->finalize(BackedTestEnum::Foo));
81+
}
82+
83+
publicfunctiontestFinalizeAnotherEnumWithEnumFqcn()
84+
{
85+
$node =newEnumNode('foo',null, [BackedTestEnum::class]);
86+
87+
$this->expectException(InvalidConfigurationException::class);
88+
$this->expectExceptionMessage('The value should be part of the "Symfony\Component\Config\Tests\Fixtures\BackedTestEnum" enum, got a value from the "Symfony\Component\Config\Tests\Fixtures\BackedTestEnum2" enum.');
89+
90+
$node->finalize(BackedTestEnum2::Foo);
91+
}
92+
93+
publicfunctiontestFinalizeWithEnumFqcnAndAnotherScalar()
94+
{
95+
$node =newEnumNode('foo',null, [BackedTestEnum::class,'another_string']);
96+
97+
$this->assertSame(BackedTestEnum::class,$node->finalize(BackedTestEnum::class));
98+
}
99+
100+
publicfunctiontestFinalizeWithEnumFqcnWorksWithPlainString()
101+
{
102+
$node =newEnumNode('foo',null, [BackedTestEnum::class]);
103+
104+
$this->assertSame(BackedTestEnum::Foo,$node->finalize('foo'));
105+
}
106+
107+
publicfunctiontestFinalizeWithEnumFqcnWithWrongCase()
108+
{
109+
$node =newEnumNode('foo',null, [BackedTestEnum::class]);
110+
111+
$this->expectException(InvalidConfigurationException::class);
112+
$this->expectExceptionMessage('The value "qux" is not allowed for path "foo". Permissible values: foo, bar');
113+
114+
$node->finalize('qux');
115+
}
116+
117+
publicfunctiontestFinalizeWithEnumFqcnWithWrongType()
118+
{
119+
$node =newEnumNode('foo',null, [BackedTestEnum::class]);
120+
121+
$this->expectException(InvalidConfigurationException::class);
122+
$this->expectExceptionMessage('The value true is not allowed for path "foo". Permissible values: foo, bar');
123+
124+
$node->finalize(true);
125+
}
126+
64127
publicfunctiontestWithPlaceHolderWithValidValue()
65128
{
66129
$node =newEnumNode('cookie_samesite',null, ['lax','strict','none']);
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespaceSymfony\Component\Config\Tests\Fixtures;
4+
5+
enum BackedTestEnum:string
6+
{
7+
case Foo ='foo';
8+
case Bar ='bar';
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespaceSymfony\Component\Config\Tests\Fixtures;
4+
5+
enum BackedTestEnum2:string
6+
{
7+
case Foo ='foo';
8+
case Bar ='bar';
9+
}

‎src/Symfony/Component/Config/Tests/Fixtures/Configuration/ExampleConfiguration.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
useSymfony\Component\Config\Definition\Builder\TreeBuilder;
1515
useSymfony\Component\Config\Definition\ConfigurationInterface;
16+
useSymfony\Component\Config\Tests\Fixtures\BackedTestEnum;
1617
useSymfony\Component\Config\Tests\Fixtures\TestEnum;
1718

1819
class ExampleConfigurationimplements ConfigurationInterface
@@ -40,6 +41,7 @@ public function getConfigTreeBuilder(): TreeBuilder
4041
->scalarNode('node_with_a_looong_name')->end()
4142
->enumNode('enum_with_default')->values(['this','that'])->defaultValue('this')->end()
4243
->enumNode('enum')->values(['this','that', TestEnum::Ccc])->end()
44+
->enumNode('enum_with_class')->enumFqcn(BackedTestEnum::class)->end()
4345
->arrayNode('array')
4446
->info('some info')
4547
->canBeUnset()

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp