Skip to content

Commit a8f32aa

Browse files
committed
[Form] Fix EnumType choice_label logic for grouped choices
1 parent c803276 commit a8f32aa

File tree

2 files changed

+119
-4
lines changed

2 files changed

+119
-4
lines changed

Extension/Core/Type/EnumType.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,15 @@ public function configureOptions(OptionsResolver $resolver): void
3131
->setAllowedValues('class', enum_exists(...))
3232
->setDefault('choices', static fn (Options $options): array => $options['class']::cases())
3333
->setDefault('choice_label', static function (Options $options) {
34-
if (\is_array($options['choices']) && !array_is_list($options['choices'])) {
35-
return null;
36-
}
34+
return static function (\UnitEnum $choice, int|string $key): string|TranslatableInterface {
35+
if (\is_int($key)) {
36+
// Key is an integer, use the enum's name (or translatable)
37+
return $choice instanceof TranslatableInterface ? $choice : $choice->name;
38+
}
3739

38-
return static fn (\UnitEnum $choice) => $choice instanceof TranslatableInterface ? $choice : $choice->name;
40+
// Key is a string, use it as the label
41+
return $key;
42+
};
3943
})
4044
->setDefault('choice_value', static function (Options $options): ?\Closure {
4145
if (!is_a($options['class'], \BackedEnum::class, true)) {

Tests/Extension/Core/Type/EnumTypeTest.php

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
namespace Extension\Core\Type;
1313

14+
use Symfony\Component\Form\ChoiceList\View\ChoiceGroupView;
15+
use Symfony\Component\Form\ChoiceList\View\ChoiceView;
1416
use Symfony\Component\Form\Extension\Core\Type\EnumType;
1517
use Symfony\Component\Form\Tests\Extension\Core\Type\BaseTypeTestCase;
1618
use Symfony\Component\Form\Tests\Fixtures\Answer;
@@ -311,6 +313,115 @@ public function testChoicesWithLabels()
311313
$this->assertSame('no', $view->children[1]->vars['label']);
312314
}
313315

316+
public function testGroupedEnumChoices()
317+
{
318+
$form = $this->factory->create($this->getTestedType(), null, [
319+
'multiple' => false,
320+
'expanded' => true,
321+
'class' => Answer::class,
322+
'choices' => [
323+
'Group 1' => [Answer::Yes, Answer::No],
324+
'Group 2' => [Answer::FourtyTwo],
325+
],
326+
]);
327+
$view = $form->createView();
328+
$this->assertCount(2, $view->vars['choices']['Group 1']->choices);
329+
$this->assertSame('Yes', $view->vars['choices']['Group 1']->choices[0]->label);
330+
$this->assertSame('No', $view->vars['choices']['Group 1']->choices[1]->label);
331+
$this->assertCount(1, $view->vars['choices']['Group 2']->choices);
332+
$this->assertSame('FourtyTwo', $view->vars['choices']['Group 2']->choices[2]->label);
333+
}
334+
335+
public function testGroupedEnumChoicesWithCustomLabels()
336+
{
337+
$form = $this->factory->create($this->getTestedType(), null, [
338+
'multiple' => false,
339+
'expanded' => true,
340+
'class' => Answer::class,
341+
'choices' => [
342+
'Group 1' => [
343+
'Custom Yes' => Answer::Yes,
344+
'Custom No' => Answer::No,
345+
],
346+
'Group 2' => [
347+
'Custom 42' => Answer::FourtyTwo,
348+
],
349+
],
350+
]);
351+
$view = $form->createView();
352+
353+
// Test Group 1
354+
$this->assertCount(2, $view->vars['choices']['Group 1']->choices);
355+
$this->assertSame('Custom Yes', $view->vars['choices']['Group 1']->choices[0]->label);
356+
$this->assertSame('Custom No', $view->vars['choices']['Group 1']->choices[1]->label);
357+
358+
// Test Group 2
359+
$this->assertCount(1, $view->vars['choices']['Group 2']->choices);
360+
$this->assertSame('Custom 42', $view->vars['choices']['Group 2']->choices[2]->label);
361+
}
362+
363+
public function testMixedGroupedAndSingleChoices()
364+
{
365+
$form = $this->factory->create($this->getTestedType(), null, [
366+
'multiple' => false,
367+
'expanded' => true,
368+
'class' => Answer::class,
369+
'choices' => [
370+
'Group 1' => [Answer::Yes, Answer::No],
371+
'Custom 42' => Answer::FourtyTwo,
372+
],
373+
]);
374+
$view = $form->createView();
375+
376+
// Group 1 (simple list) → enum names
377+
$this->assertInstanceOf(ChoiceGroupView::class, $view->vars['choices']['Group 1']);
378+
$this->assertCount(2, $view->vars['choices']['Group 1']->choices);
379+
$this->assertSame('Yes', $view->vars['choices']['Group 1']->choices[0]->label);
380+
$this->assertSame('No', $view->vars['choices']['Group 1']->choices[1]->label);
381+
382+
// Single custom → custom label (treated as flat choice)
383+
$customChoice = $view->vars['choices'][2];
384+
$this->assertInstanceOf(ChoiceView::class, $customChoice);
385+
$this->assertSame('Custom 42', $customChoice->label);
386+
}
387+
388+
public function testMixedLabeledAndUnlabeledChoices()
389+
{
390+
$form = $this->factory->create($this->getTestedType(), null, [
391+
'multiple' => false,
392+
'expanded' => true,
393+
'class' => Answer::class,
394+
'choices' => [
395+
Answer::Yes,
396+
Answer::No,
397+
'Custom 42' => Answer::FourtyTwo,
398+
],
399+
]);
400+
$view = $form->createView();
401+
// Assertions: names for unlabeled, custom for labeled
402+
$children = array_values($view->children); // Numeric access
403+
$this->assertSame('Yes', $children[0]->vars['label']);
404+
$this->assertSame('No', $children[1]->vars['label']);
405+
$this->assertSame('Custom 42', $children[2]->vars['label']);
406+
}
407+
408+
public function testEnumChoicesWithNumericCustomLabels()
409+
{
410+
$form = $this->factory->create($this->getTestedType(), null, [
411+
'multiple' => false,
412+
'expanded' => true,
413+
'class' => Answer::class,
414+
'choice_label' => null, // Explicitly override to use keys as labels for numeric customs
415+
'choices' => [
416+
'34' => Answer::Yes,
417+
'2' => Answer::No,
418+
],
419+
]);
420+
$view = $form->createView();
421+
$this->assertSame('34', $view->children[0]->vars['label']);
422+
$this->assertSame('2', $view->children[1]->vars['label']);
423+
}
424+
314425
protected function getTestOptions(): array
315426
{
316427
return ['class' => Suit::class];

0 commit comments

Comments
 (0)