10000 feature #43095 [Form] Add the EnumType (derrabus) · symfony/symfony@ca37eec · GitHub
[go: up one dir, main page]

Skip to content

Commit ca37eec

Browse files
committed
feature #43095 [Form] Add the EnumType (derrabus)
This PR was merged into the 5.4 branch. Discussion ---------- [Form] Add the EnumType | Q | A | ------------- | --- | Branch? | 5.4 | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | N/A | License | MIT | Doc PR | TODO This PR adds a new `EnumType` that enables the form component to configure a `ChoiceType` for a native PHP enum. Example: ```php enum Suit: string { case Hearts = 'H'; case Diamonds = 'D'; case Clubs = 'C'; case Spades = 'S'; } enum Rank: string { case Ace = 'A'; case King = 'K'; case Queen = 'Q'; case Jack = 'J'; case Ten = 'X'; case Nine = '9'; case Eight = '8'; case Seven = '7'; case Six = '6'; case Five = '5'; case Four = '4'; case Three = '3'; case Two = '2'; } final class Card { public ?Suit $suit = null; public ?Rank $rank = null; } ``` ```php $form = $this ->createFormBuilder(null, ['data_class' => Card::class]) ->add('suit', EnumType::class, ['class' => Suit::class, 'required' => false, 'expanded' => true]) ->add('rank', EnumType::class, ['class' => Rank::class, 'required' => false]) ->add('submit', SubmitType::class) ->getForm() ->handleRequest($request) ; ``` <img width="768" alt="Bildschirmfoto 2021-09-19 um 18 06 39" src="https://user-images.githubusercontent.com/1506493/133934643-8dafc743-da5a-44a6-8ed7-3333e9a66317.png"> Commits ------- c6edc34 [Form] Add the EnumType
2 parents eb324a1 + c6edc34 commit ca37eec

File tree

10 files changed

+423
-28
lines changed

10 files changed

+423
-28
lines changed

.github/patch-types.php

Lines changed: 3 additions & 0 deletions
Original file line number< D7AF /th>Diff line numberDiff line change
@@ -30,6 +30,9 @@
3030
case false !== strpos($file, '/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Prototype/BadClasses/MissingParent.php'):
3131
case false !== strpos($file, '/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/'):
3232
case false !== strpos($file, '/src/Symfony/Component/ErrorHandler/Tests/Fixtures/'):
33+
case false !== strpos($file, '/src/Symfony/Component/Form/Tests/Fixtures/Answer.php'):
34+
case false !== strpos($file, '/src/Symfony/Component/Form/Tests/Fixtures/Number.php'):
35+
case false !== strpos($file, '/src/Symfony/Component/Form/Tests/Fixtures/Suit.php'):
3336
case false !== strpos($file, '/src/Symfony/Component/PropertyInfo/Tests/Fixtures/'):
3437
case false !== strpos($file, '/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php81Dummy.php'):
3538
case false !== strpos($file, '/src/Symfony/Component/Runtime/Internal/ComposerPlugin.php'):

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
"symfony/polyfill-mbstring": "~1.0",
5353
"symfony/polyfill-php73": "^1.11",
5454
"symfony/polyfill-php80": "^1.16",
55-
"symfony/polyfill-php81": "^1.22",
55+
"symfony/polyfill-php81": "^1.23",
5656
"symfony/polyfill-uuid": "^1.15"
5757
},
5858
"replace": {

src/Symfony/Component/Form/CHANGELOG.md

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

77
* Deprecate calling `FormErrorIterator::children()` if the current element is not iterable.
88
* Allow to pass `TranslatableMessage` objects to the `help` option
9+
* Add the `EnumType`
910

1011
5.3
1112
---
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Form\Extension\Core\Type;
13+
14+
use Symfony\Component\Form\AbstractType;
15+
use Symfony\Component\OptionsResolver\Options;
16+
use Symfony\Component\OptionsResolver\OptionsResolver;
17+
18+
/**
19+
* A choice type for native PHP enums.
20+
*
21+
* @author Alexander M. Turek <me@derrabus.de>
22+
*/
23+
final class EnumType extends AbstractType
24+
{
25+
public function configureOptions(OptionsResolver $resolver): void
26+
{
27+
$resolver
28+
->setRequired(['class'])
29+
->setAllowedTypes('class', 'string')
30+
->setAllowedValues('class', \Closure::fromCallable('enum_exists'))
31+
->setDefault('choices', static function (Options $options): array {
32+
return $options['class']::cases();
33+
})
34+
->setDefault('choice_label', static function (\UnitEnum $choice): string {
35+
return $choice->name;
36+
})
37+
->setDefault('choice_value', static function (Options $options): ?\Closure {
38+
if (!is_a($options['class'], \BackedEnum::class, true)) {
39+
return null;
40+
}
41+
42+
return static function (?\BackedEnum $choice): ?string {
43+
if (null === $choice) {
44+
return null;
45+
}
46+
47+
return (string) $choice->value;
48+
};
49+
})
50+
;
51+
}
52+
53+
public function getParent(): string
54+
{
55+
return ChoiceType::class;
56+
}
57+
}

src/Symfony/Component/Form/Tests/Extension/Core/Type/BaseTypeTest.php

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@ abstract class BaseTypeTest extends TypeTestCase
2525

2626
public function testPassDisabledAsOption()
2727
{
28-
$form = $this->factory->create($this->getTestedType(), null, ['disabled' => true]);
28+
$form = $this->factory->create($this->getTestedType(), null, array_merge($this->getTestOptions(), ['disabled' => true]));
2929

3030
$this->assertTrue($form->isDisabled());
3131
}
3232

3333
public function testPassIdAndNameToView()
3434
{
35-
$view = $this->factory->createNamed('name', $this->getTestedType())
35+
$view = $this->factory->createNamed('name', $this->getTestedType(), null, $this->getTestOptions())
3636
->createView();
3737

3838
$this->assertEquals('name', $view->vars['id']);
@@ -42,7 +42,7 @@ public function testPassIdAndNameToView()
4242

4343
public function testStripLeadingUnderscoresAndDigitsFromId()
4444
{
45-
$view = $this->factory->createNamed('_09name', $this->getTestedType())
45+
$view = $this->factory->createNamed('_09name', $this->getTestedType(), null, $this->getTestOptions())
4646
->createView();
4747

4848
$this->assertEquals('name', $view->vars['id']);
@@ -53,7 +53,7 @@ public function testStripLeadingUnderscoresAndDigitsFromId()
5353
public function testPassIdAndNameToViewWithParent()
5454
{
5555
$view = $this->factory->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE)
56-
->add('child', $this->getTestedType())
56+
->add('child', $this->getTestedType(), $this->getTestOptions())
5757
->getForm()
5858
->createView();
5959

@@ -66,7 +66,7 @@ public function testPassIdAndNameToViewWithGrandParent()
6666
{
6767
$builder = $this->factory->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE)
6868
->add('child', FormTypeTest::TESTED_TYPE);
69-
$builder->get('child')->add('grand_child', $this->getTestedType());
69+
$builder->get('child')->add('grand_child', $this->getTestedType(), $this->getTestOptions());
7070
$view = $builder->getForm()->createView();
7171

7272
$this->assertEquals('parent_child_grand_child', $view['child']['grand_child']->vars['id']);
@@ -76,9 +76,9 @@ public function testPassIdAndNameToViewWithGrandParent()
7676

7777
public function testPassTranslationDomainToView()
7878
{
79-
$view = $this->factory->create($this->getTestedType(), null, [
79+
$view = $this->factory->create($this->getTestedType(), null, array_merge($this->getTestOptions(), [
8080
'translation_domain' => 'domain',
81-
])
81+
]))
8282
->createView();
8383

8484
$this->assertSame('domain', $view->vars['translation_domain']);
@@ -90,7 +90,7 @@ public function testInheritTranslationDomainFromParent()
9090
->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE, null, [
9191
'translation_domain' => 'domain',
9292
])
93-
->add('child', $this->getTestedType())
93+
->add('child', $this->getTestedType(), $this->getTestOptions())
9494
->getForm()
9595
->createView();
9696

@@ -103,9 +103,9 @@ public function testPreferOwnTranslationDomain()
103103
->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE, null, [
104104
'translation_domain' => 'parent_domain',
105105
])
106-
->add('child', $this->getTestedType(), [
106+
->add('child', $this->getTestedType(), array_merge($this->getTestOptions(), [
107107
'translation_domain' => 'domain',
108-
])
108+
]))
109109
->getForm()
110110
->createView();
111111

@@ -115,7 +115,7 @@ public function testPreferOwnTranslationDomain()
115115
public function testDefaultTranslationDomain()
116116
{
117117
$view = $this->factory->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE)
118-
->add('child', $this->getTestedType())
118+
->add('child', $this->getTestedType(), $this->getTestOptions())
119119
->getForm()
10000
120120
->createView();
121121

@@ -126,9 +126,9 @@ public function testPassLabelTranslationParametersToView()
126126
{
127127
$this->requiresFeatureSet(403);
128128

129-
$view = $this->factory->create($this->getTestedType(), null, [
129+
$view = $this->factory->create($this->getTestedType(), null, array_merge($this->getTestOptions(), [
130130
'label_translation_parameters' => ['%param%' => 'value'],
131-
])
131+
]))
132132
->createView();
133133

134134
$this->assertSame(['%param%' => 'value'], $view->vars['label_translation_parameters']);
@@ -138,9 +138,9 @@ public function testPassAttrTranslationParametersToView()
138138
{
139139
$this->requiresFeatureSet(403);
140140

141-
$view = $this->factory->create($this->getTestedType(), null, [
141+
$view = $this->factory->create($this->getTestedType(), null, array_merge($this->getTestOptions(), [
142142
'attr_translation_parameters' => ['%param%' => 'value'],
143-
])
143+
]))
144144
->createView();
145145

146146
$this->assertSame(['%param%' => 'value'], $view->vars['attr_translation_parameters']);
@@ -154,7 +154,7 @@ public function testInheritLabelTranslationParametersFromParent()
154154
->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE, null, [
155155
'label_translation_parameters' => ['%param%' => 'value'],
156156
])
157-
->add('child', $this->getTestedType())
157+
->add('child', $this->getTestedType(), $this->getTestOptions())
158158
->getForm()
159159
->createView();
160160

@@ -169,7 +169,7 @@ public function testInheritAttrTranslationParametersFromParent()
169169
->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE, null, [
170170
'attr_translation_parameters' => ['%param%' => 'value'],
171171
])
172-
->add('child', $this->getTestedType())
172+
->add('child', $this->getTestedType(), $this->getTestOptions())
173173
->getForm()
174174
->createView();
175175

@@ -184,9 +184,9 @@ public function testPreferOwnLabelTranslationParameters()
184184
->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE, null, [
185185
'label_translation_parameters' => ['%parent_param%' => 'parent_value', '%override_param%' => 'parent_override_value'],
186186
])
187-
->add('child', $this->getTestedType(), [
187+
->add('child', $this->getTestedType(), array_merge($this->getTestOptions(), [
188188
'label_translation_parameters' => ['%override_param%' => 'child_value'],
189-
])
189+
]))
190190
->getForm()
191191
->createView();
192192

@@ -201,9 +201,9 @@ public function testPreferOwnAttrTranslationParameters()
201201
->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE, null, [
202202
'attr_translation_parameters' => ['%parent_param%' => 'parent_value', '%override_param%' => 'parent_override_value'],
203203
])
204-
->add('child', $this->getTestedType(), [
204+
->add('child', $this->getTestedType(), array_merge($this->getTestOptions(), [
205205
'attr_translation_parameters' => ['%override_param%' => 'child_value'],
206-
])
206+
]))
207207
->getForm()
208208
->createView();
209209

@@ -215,7 +215,7 @@ public function testDefaultLabelTranslationParameters()
215215
$this->requiresFeatureSet(403);
216216

217217
$view = $this->factory->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE)
218-
->add('child', $this->getTestedType())
218+
->add('child', $this->getTestedType(), $this->getTestOptions())
219219
->getForm()
220220
->createView();
221221

@@ -227,7 +227,7 @@ public function testDefaultAttrTranslationParameters()
227227
$this->requiresFeatureSet(403);
228228

229229
$view = $this->factory->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE)
230-
->add('child', $this->getTestedType())
230+
->add('child', $this->getTestedType(), $this->getTestOptions())
231231
->getForm()
232232
->createView();
233233

@@ -236,23 +236,26 @@ public function testDefaultAttrTranslationParameters()
236236

237237
public function testPassLabelToView()
238238
{
239-
$view = $this->factory->createNamed('__test___field', $this->getTestedType(), null, ['label' => 'My label'])
239+
$view = $this->factory->createNamed('__test___field', $this->getTestedType(), null, array_merge(
240+
$this->getTestOptions(),
241+
['label' => 'My label']
242+
))
240243
->createView();
241244

242245
$this->assertSame('My label', $view->vars['label']);
243246
}
244247

245248
public function testPassMultipartFalseToView()
246249
{
247-
$view = $this->factory->create($this->getTestedType())
250+
$view = $this->factory->create($this->getTestedType(), null, $this->getTestOptions())
248251
->createView();
249252

250253
$this->assertFalse($view->vars['multipart']);
251254
}
252255

253256
public function testSubmitNull($expected = null, $norm = null, $view = null)
254257
{
255-
$form = $this->factory->create($this->getTestedType());
258+
$form = $this->factory->create($this->getTestedType(), null, $this->getTestOptions());
256259
$form->submit(null);
257260

258261
$this->assertSame($expected, $form->getData());
@@ -262,7 +265,7 @@ public function testSubmitNull($expected = null, $norm = null, $view = null)
262265

263266
public function testSubmitNullUsesDefaultEmptyData($emptyData = 'empty', $expectedData = null)
264267
{
265-
$builder = $this->factory->createBuilder($this->getTestedType());
268+
$builder = $this->factory->createBuilder($this->getTestedType(), null, $this->getTestOptions());
266269

267270
if ($builder->getCompound()) {
268271
$emptyData = [];
@@ -286,4 +289,9 @@ protected function getTestedType()
286289
{
287290
return static::TESTED_TYPE;
288291
}
292+
293+
protected function getTestOptions(): array
294+
{
295+
return [];
296+
}
289297
}

0 commit comments

Comments
 (0)
0