loadBookingCreateDto($this->bookingSessionService, $request); } catch (BookingSessionNotFoundException|TravelNotFoundException|HotelNotInTravelException $exception) { return $this->createBookingCreateFailureResponse($exception, false); } // Validate step access if (null !== $redirect = $this->validateStepAccess($bookingCreateDto, 2)) { return $redirect; } // Enrich with fresh availability data $this->travelDataService->enrichWithFreshAvailabilities($bookingCreateDto->travel); // Ensure correct number of participants first, then prepopulate the applicant if needed. $this->ensureCorrectNumberOfParticipants($bookingCreateDto); $user = $this->getUser(); if ($user instanceof User && isset($bookingCreateDto->participants[0]) && $this->prepopulationService->shouldPrefillApplicant($bookingCreateDto->participants[0])) { $bookingCreateDto->participants[0] = $this->prepopulationService->prefillApplicantFromUser( $user, $bookingCreateDto->participants[0] ); } // Validate room assignments against current selection (handles back-navigation from step 2 to step 1) $this->roomAssignmentService->validateAndResetInvalidAssignments($bookingCreateDto); // Auto-assign rooms if needed $this->roomAssignmentService->assignRoomsIfNeeded($bookingCreateDto); // Preselect mandatory services $this->bookingService->preselectDefaultServices($bookingCreateDto); $this->bookingService->applyCreateBookingStatusRules($bookingCreateDto); // Save BookingDto to session $this->bookingSessionService->saveBookingDto($request, $bookingCreateDto, BookingDto::MODE_CREATE); // Create validation form $form = $this->createForm(BookingCreateStep2Type::class, $bookingCreateDto); $form->handleRequest($request); // Handle form submission if (true === $form->isSubmitted() && true === $form->isValid()) { // All participants validated successfully, update current step $bookingCreateDto->currentStep = 3; $this->bookingSessionService->saveBookingDto($request, $bookingCreateDto, BookingDto::MODE_CREATE); // Proceed to Step 3 return $this->redirectToRoute('app_booking_create_step_3'); } $context = $this->createContextFactory->createWithParticipantCards($bookingCreateDto, $form->isSubmitted()); $templateData = [ 'form' => $form->createView(), 'bookingCreateContext' => $context, ]; return $this->render('booking/create/step_2.html.twig', $templateData); } /** * Ensures the booking DTO has the expected number of participant objects based on room selections. */ private function ensureCorrectNumberOfParticipants(BookingDto $bookingDto): void { $participantsCount = $this->calculateParticipantsCount($bookingDto->roomSelections, $bookingDto->travel); $existingParticipants = $bookingDto->participants; $bookingDto->participants = []; for ($i = 0; $i < $participantsCount; ++$i) { $participant = $existingParticipants[$i] ?? new ParticipantDto(); $participant->index = $i; $bookingDto->participants[$i] = $participant; } } /** * @param array $roomSelections */ private function calculateParticipantsCount(array $roomSelections, Travel $travelData): int { $participantsCount = 0; $rooms = $travelData->getAvailableRooms(); foreach ($roomSelections as $roomSelection) { $room = $rooms[$roomSelection->id]; $participantsCount += $room->minPax * $roomSelection->quantity; } return $participantsCount; } }