Skip to content

Commit

Permalink
[LiveComponent] Fix ComponentWithFormTrait::extractFormValues() wit…
Browse files Browse the repository at this point in the history
…h edge cases
  • Loading branch information
smnandre committed Jan 8, 2025
1 parent 8fcac2a commit 2c6a96f
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 13 deletions.
40 changes: 27 additions & 13 deletions src/LiveComponent/src/ComponentWithFormTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace Symfony\UX\LiveComponent;

use Symfony\Component\Form\ChoiceList\View\ChoiceGroupView;
use Symfony\Component\Form\ClearableErrorsInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
Expand Down Expand Up @@ -255,25 +256,38 @@ private function extractFormValues(FormView $formView): array
continue;
}

// <input type="checkbox">
if (\array_key_exists('checked', $child->vars)) {
// special handling for check boxes
$values[$name] = $child->vars['checked'] ? $child->vars['value'] : null;
continue;
}

if (\array_key_exists('choices', $child->vars)
&& $child->vars['required']
&& !$child->vars['disabled']
&& !$child->vars['value']
&& (false === $child->vars['placeholder'] || null === $child->vars['placeholder'])
&& !$child->vars['multiple']
&& !$child->vars['expanded']
&& $child->vars['choices']
// <select> - Simulate browser behavior
// When no option is selected, browsers send the value of the first
// option, when the following conditions are met:
if (
isset($child->vars['choices']) // has defined choices
&& $child->vars['required'] // is required
&& !$child->vars['disabled'] // is not disabled
&& '' === $child->vars['value'] // has no value set ("0" can be a value)
&& !array_diff_key(
/* @see \Symfony\Component\Form\Extension\Core\Type\ChoiceType::buildView() */
array_flip(['choices', 'expanded', 'multiple', 'placeholder', 'placeholder_in_choices', 'preferred_choices']),
$child->vars,
)
&& !$child->vars['expanded'] // is a <select> (not a radio/checkbox)
&& !$child->vars['multiple'] // is not multiple
&& !is_string($child->vars['placeholder']) // has no placeholder (empty string is valid)
) {
if (null !== $firstKey = array_key_first($child->vars['choices'])) {
$values[$name] = $child->vars['choices'][$firstKey]->value ?? null;
}

$choices = $child->vars['choices'];
do {
$choice = $choices[array_key_first($choices)];
if (!$choice instanceof ChoiceGroupView) {
break;
}
} while ($choices = $choice->choices);

$values[$name] = $choice?->value;
continue;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,15 @@ public function buildForm(FormBuilderInterface $builder, array $options)
'foo' => 1,
],
])
->add('choice_required_without_placeholder_and_choice_group', ChoiceType::class, [
'choices' => [
'Bar Group' => [
'Bar Label' => 'ok',
'Foo Label' => 'foo_value',
],
'foo' => 1,
],
])
->add('choice_expanded', ChoiceType::class, [
'choices' => [
'foo' => 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ public function testHandleCheckboxChanges(): void
'choice_required_with_placeholder' => '',
'choice_required_with_empty_placeholder' => '',
'choice_required_without_placeholder' => '2',
'choice_required_without_placeholder_and_choice_group' => 'ok',
'choice_expanded' => '',
'choice_multiple' => ['2'],
'select_multiple' => ['2'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public function testFormValues(): void
'choice_required_with_placeholder' => '',
'choice_required_with_empty_placeholder' => '',
'choice_required_without_placeholder' => '2',
'choice_required_without_placeholder_and_choice_group' => 'ok',
'choice_expanded' => '',
'choice_multiple' => ['2'],
'select_multiple' => ['2'],
Expand Down

0 comments on commit 2c6a96f

Please sign in to comment.