diff --git a/src/LiveComponent/src/ComponentWithFormTrait.php b/src/LiveComponent/src/ComponentWithFormTrait.php index 00d981decd..0e088e0223 100644 --- a/src/LiveComponent/src/ComponentWithFormTrait.php +++ b/src/LiveComponent/src/ComponentWithFormTrait.php @@ -258,9 +258,26 @@ private function extractFormValues(FormView $formView): array if (\array_key_exists('checked', $child->vars)) { // special handling for check boxes $values[$name] = $child->vars['checked'] ? $child->vars['value'] : null; - } else { - $values[$name] = $child->vars['value']; + continue; + } + + if (\array_key_exists('choices', $child->vars) + && $child->vars['required'] + && !$child->vars['disabled'] + && !$child->vars['value'] + && !$child->vars['placeholder'] + && !$child->vars['multiple'] + && !$child->vars['expanded'] + && $child->vars['choices'] + ) { + if (null !== $firstKey = array_key_first($child->vars['choices'])) { + $values[$name] = $child->vars['choices'][$firstKey]->value ?? null; + } + + continue; } + + $values[$name] = $child->vars['value']; } return $values; diff --git a/src/LiveComponent/tests/Fixtures/Factory/CategoryFixtureEntityFactory.php b/src/LiveComponent/tests/Fixtures/Factory/CategoryFixtureEntityFactory.php new file mode 100644 index 0000000000..ccc7d8d7e7 --- /dev/null +++ b/src/LiveComponent/tests/Fixtures/Factory/CategoryFixtureEntityFactory.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\UX\LiveComponent\Tests\Fixtures\Factory; + +use Symfony\UX\LiveComponent\Tests\Fixtures\Entity\CategoryFixtureEntity; +use Zenstruck\Foundry\Persistence\PersistentProxyObjectFactory; + +final class CategoryFixtureEntityFactory extends PersistentProxyObjectFactory +{ + protected function defaults(): array|callable + { + return [ + 'name' => self::faker()->name(), + ]; + } + + public static function class(): string + { + return CategoryFixtureEntity::class; + } +} diff --git a/src/LiveComponent/tests/Fixtures/Form/FormWithManyDifferentFieldsType.php b/src/LiveComponent/tests/Fixtures/Form/FormWithManyDifferentFieldsType.php index ea69b1386e..0524f957a1 100644 --- a/src/LiveComponent/tests/Fixtures/Form/FormWithManyDifferentFieldsType.php +++ b/src/LiveComponent/tests/Fixtures/Form/FormWithManyDifferentFieldsType.php @@ -11,6 +11,7 @@ namespace Symfony\UX\LiveComponent\Tests\Fixtures\Form; +use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; @@ -22,6 +23,7 @@ use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Validator\Constraints\Length; +use Symfony\UX\LiveComponent\Tests\Fixtures\Entity\CategoryFixtureEntity; /** * @author Jakub Caban @@ -41,6 +43,20 @@ public function buildForm(FormBuilderInterface $builder, array $options) 'foo' => 1, 'bar' => 2, ], + 'required' => false, + ]) + ->add('choice_required_with_placeholder', ChoiceType::class, [ + 'choices' => [ + 'bar' => 2, + 'foo' => 1, + ], + 'placeholder' => 'foo', + ]) + ->add('choice_required_without_placeholder', ChoiceType::class, [ + 'choices' => [ + 'bar' => 2, + 'foo' => 1, + ], ]) ->add('choice_expanded', ChoiceType::class, [ 'choices' => [ @@ -64,6 +80,10 @@ public function buildForm(FormBuilderInterface $builder, array $options) ], 'multiple' => true, ]) + ->add('entity', EntityType::class, [ + 'class' => CategoryFixtureEntity::class, + 'choice_label' => 'name', + ]) ->add('checkbox', CheckboxType::class) ->add('checkbox_checked', CheckboxType::class) ->add('file', FileType::class) diff --git a/src/LiveComponent/tests/Functional/Form/ComponentWithFormTest.php b/src/LiveComponent/tests/Functional/Form/ComponentWithFormTest.php index ca0bb583a4..f13be55116 100644 --- a/src/LiveComponent/tests/Functional/Form/ComponentWithFormTest.php +++ b/src/LiveComponent/tests/Functional/Form/ComponentWithFormTest.php @@ -15,6 +15,7 @@ use Symfony\Component\DomCrawler\Crawler; use Symfony\Component\Form\FormFactoryInterface; use Symfony\UX\LiveComponent\Tests\Fixtures\Component\FormWithCollectionTypeComponent; +use Symfony\UX\LiveComponent\Tests\Fixtures\Factory\CategoryFixtureEntityFactory; use Symfony\UX\LiveComponent\Tests\Fixtures\Form\BlogPostFormType; use Symfony\UX\LiveComponent\Tests\LiveComponentTestHelper; use Zenstruck\Browser\Test\HasBrowser; @@ -157,6 +158,9 @@ public function testFormRemembersValidationFromInitialForm(): void public function testHandleCheckboxChanges(): void { + $category = CategoryFixtureEntityFactory::createMany(5); + $id = $category[0]->getId(); + $mounted = $this->mountComponent( 'form_with_many_different_fields_type', [ @@ -174,9 +178,12 @@ public function testHandleCheckboxChanges(): void 'textarea' => '', 'range' => '', 'choice' => '', + 'choice_required_with_placeholder' => '', + 'choice_required_without_placeholder' => '2', 'choice_expanded' => '', 'choice_multiple' => ['2'], 'select_multiple' => ['2'], + 'entity' => (string) $id, 'checkbox' => null, 'checkbox_checked' => '1', 'file' => '', @@ -296,6 +303,7 @@ public function testLiveCollectionTypeAddButtonsByDefault(): void public function testResetForm(): void { + CategoryFixtureEntityFactory::createMany(5); $mounted = $this->mountComponent('form_with_many_different_fields_type'); $dehydratedProps = $this->dehydrateComponent($mounted)->getProps(); diff --git a/src/LiveComponent/tests/Functional/Test/InteractsWithLiveComponentsTest.php b/src/LiveComponent/tests/Functional/Test/InteractsWithLiveComponentsTest.php index b6c6ef6ce8..6bae36f925 100644 --- a/src/LiveComponent/tests/Functional/Test/InteractsWithLiveComponentsTest.php +++ b/src/LiveComponent/tests/Functional/Test/InteractsWithLiveComponentsTest.php @@ -17,6 +17,8 @@ use Symfony\Component\Security\Http\Attribute\IsGranted; use Symfony\UX\LiveComponent\Test\InteractsWithLiveComponents; use Symfony\UX\LiveComponent\Tests\Fixtures\Component\Component2; +use Symfony\UX\LiveComponent\Tests\Fixtures\Factory\CategoryFixtureEntityFactory; +use Zenstruck\Foundry\Test\ResetDatabase; /** * @author Kevin Bond @@ -24,6 +26,7 @@ final class InteractsWithLiveComponentsTest extends KernelTestCase { use InteractsWithLiveComponents; + use ResetDatabase; public function testCanRenderInitialData(): void { @@ -172,6 +175,7 @@ public function testActingAs(): void public function testCanSubmitForm(): void { + CategoryFixtureEntityFactory::createMany(5); $testComponent = $this->createLiveComponent('form_with_many_different_fields_type'); $response = $testComponent->submitForm(['form' => ['text' => 'foobar']])->response(); diff --git a/src/LiveComponent/tests/Unit/Form/ComponentWithFormTest.php b/src/LiveComponent/tests/Unit/Form/ComponentWithFormTest.php index 2c25ac5ffd..2cf89e3e43 100644 --- a/src/LiveComponent/tests/Unit/Form/ComponentWithFormTest.php +++ b/src/LiveComponent/tests/Unit/Form/ComponentWithFormTest.php @@ -13,14 +13,21 @@ use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; use Symfony\UX\LiveComponent\Tests\Fixtures\Component\FormComponentWithManyDifferentFieldsType; +use Symfony\UX\LiveComponent\Tests\Fixtures\Factory\CategoryFixtureEntityFactory; +use Zenstruck\Foundry\Test\ResetDatabase; /** * @author Jakub Caban */ class ComponentWithFormTest extends KernelTestCase { + use ResetDatabase; + public function testFormValues(): void { + $category = CategoryFixtureEntityFactory::createMany(5); + $id = $category[0]->getId(); + $formFactory = self::getContainer()->get('form.factory'); $component = new FormComponentWithManyDifferentFieldsType($formFactory); $component->initialData = [ @@ -36,9 +43,12 @@ public function testFormValues(): void 'textarea' => '', 'range' => '', 'choice' => '', + 'choice_required_with_placeholder' => '', + 'choice_required_without_placeholder' => '2', 'choice_expanded' => '', 'choice_multiple' => ['2'], 'select_multiple' => ['2'], + 'entity' => (string) $id, 'checkbox' => null, 'checkbox_checked' => '1', 'file' => '',