roomSelections as $roomSelection) { if (null !== $roomSelection->quantity && $roomSelection->quantity > 0) { ++$selectedRoomTypeCount; } } return 1 === $selectedRoomTypeCount; } /** * Automatically assigns participants to rooms based on selected room quantities and capacities. * * Assignment algorithm: * - Iterates through selected rooms in order * - For each room quantity, assigns minPax participants to that room ID * - Ensures sequential assignment (participant 0, 1, 2, etc.) * * Example: * - 2x "Doppelzimmer" (capacity 2) = participants 0-1 → room A, participants 2-3 → room A * - 1x "3-Bett-Zimmer" (capacity 3) = participants 4-6 → room B * * Note: Only performs assignment if shouldAutoAssignRooms() returns true. * * @param BookingDto $dto The booking DTO containing room selections and participants */ public function assignParticipantsToRooms(BookingDto $dto): void { // Skip auto-assignment if multiple room types selected if (false === $this->shouldAutoAssignRooms($dto)) { return; } $participantIndex = 0; $selectedRooms = $dto->getSelectedRooms(); $availableRooms = $dto->travel->getAvailableRooms(); foreach ($selectedRooms as $roomSelection) { $room = $availableRooms[$roomSelection->id] ?? null; if (null === $room) { continue; // Skip if room not found } $capacityPerRoom = $room->minPax ?? 1; // Assign participants for each room quantity for ($i = 0; $i < $roomSelection->quantity; ++$i) { // Assign participants according to room capacity for ($j = 0; $j < $capacityPerRoom; ++$j) { if (isset($dto->participants[$participantIndex])) { $dto->participants[$participantIndex]->assignedRoomId = $room->id; ++$participantIndex; } } } } } /** * Assigns rooms to participants if any participants need room assignment. * * Checks if any participants have null room assignments, and if so, * triggers the auto-assignment process. This is a convenience method * that combines the check and assignment into a single call. * * @param BookingDto $dto The booking DTO to update * * @return bool True if assignment was performed, false if not needed */ public function assignRoomsIfNeeded(BookingDto $dto): bool { foreach ($dto->participants as $participant) { if (null === $participant->assignedRoomId) { $this->assignParticipantsToRooms($dto); return true; } } return false; } /** * Validates and resets room assignments that reference rooms no longer selected. * * This method ensures room assignments remain valid after room selection changes in Step 1. * When a user goes back to Step 1 and changes room selections, existing assignments may * reference room IDs that are no longer in the selected rooms list. This method detects * such invalid assignments and resets them to null. * * @param BookingDto $dto The booking DTO to validate * * @return bool True if any assignments were reset, false if all were valid */ public function validateAndResetInvalidAssignments(BookingDto $dto): bool { $selectedRoomIds = $this->getSelectedRoomIds($dto); $resetOccurred = false; foreach ($dto->participants as $participant) { if (null !== $participant->assignedRoomId && false === in_array($participant->assignedRoomId, $selectedRoomIds, true)) { $participant->assignedRoomId = null; $resetOccurred = true; } } return $resetOccurred; } /** * Gets the list of room IDs from currently selected rooms. * * @param BookingDto $dto The booking DTO containing room selections * * @return array Array of selected room IDs */ private function getSelectedRoomIds(BookingDto $dto): array { $ids = []; foreach ($dto->getSelectedRooms() as $roomSelection) { $ids[] = $roomSelection->id; } return $ids; } }