From e8c27cb51b3da28510ffbad96410662b34564dcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Fromme?= Date: Wed, 23 Jul 2025 11:08:29 +0200 Subject: [PATCH] wip: refactoring --- src/Form/BookingCreateStep2Type.php | 81 +++++++++++++++++++++++------ 1 file changed, 65 insertions(+), 16 deletions(-) diff --git a/src/Form/BookingCreateStep2Type.php b/src/Form/BookingCreateStep2Type.php index d8614c4..93fdfc3 100644 --- a/src/Form/BookingCreateStep2Type.php +++ b/src/Form/BookingCreateStep2Type.php @@ -8,31 +8,80 @@ use Symfony\Component\Form\Extension\Core\Type\CollectionType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; +use Symfony\Component\Form\FormInterface; use Symfony\Component\OptionsResolver\OptionsResolver; class BookingCreateStep2Type extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options): void { - $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { - /** @var BookingCreateDto|null $data */ - $data = $event->getData(); - $form = $event->getForm(); + $builder + ->addEventListener(FormEvents::PRE_SET_DATA, [$this, 'onPreSetData']) + ->addEventListener(FormEvents::PRE_SUBMIT, [$this, 'onPreSubmit']) + ; + } - if (null === $data) { - return; + /** + * Handles the initial form creation. + */ + public function onPreSetData(FormEvent $event): void + { + /** @var BookingCreateDto|null $data */ + $data = $event->getData(); + if (null === $data) { + return; + } + + $this->addParticipantsField($event->getForm(), $data); + } + + /** + * Handles dynamic updates on POST requests (e.g., from HTMX). + * + * This listener synchronizes the DTO with the submitted data *before* + * the form's children are processed. It then rebuilds the participants + * field to ensure choice loaders are created with the fresh state. + */ + public function onPreSubmit(FormEvent $event): void + { + $form = $event->getForm(); + $submittedData = $event->getData(); + + /** @var BookingCreateDto $bookingDto */ + $bookingDto = $form->getData(); + + // If participant data isn't in the submission, we can't do anything. + if (!isset($submittedData['participants']) || !is_array($submittedData['participants'])) { + return; + } + + // Manually update the DTO with the submitted room assignments. + foreach ($submittedData['participants'] as $index => $participantData) { + if (isset($participantData['assignedRoomId']) && isset($bookingDto->participants[$index])) { + $roomId = $participantData['assignedRoomId']; + // An unselected choice submits an empty string. + $bookingDto->participants[$index]->assignedRoomId = '' === $roomId ? null : (int) $roomId; } + } - $form->add('participants', CollectionType::class, [ - 'entry_type' => BookingCreateParticipantType::class, - 'allow_add' => false, - 'allow_delete' => false, - 'by_reference' => false, - 'entry_options' => [ - 'selected_rooms' => $data->getSelectedRooms(), - ], - ]); - }); + // Now, rebuild the 'participants' field with the updated DTO. + $this->addParticipantsField($form, $bookingDto); + } + + /** + * Adds or replaces the 'participants' collection field on the form. + */ + private function addParticipantsField(FormInterface $form, BookingCreateDto $data): void + { + $form->add('participants', CollectionType::class, [ + 'entry_type' => BookingCreateParticipantType::class, + 'allow_add' => false, + 'allow_delete' => false, + 'by_reference' => false, + 'entry_options' => [ + 'selected_rooms' => $data->getSelectedRooms(), + ], + ]); } public function configureOptions(OptionsResolver $resolver): void