158 lines
5.4 KiB
PHP
158 lines
5.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Service;
|
|
|
|
use App\Form\Model\BookingDto;
|
|
|
|
/**
|
|
* Handles automatic room assignment for booking participants.
|
|
*
|
|
* This service automatically assigns participants to selected rooms based on room capacity
|
|
* and quantity, eliminating the need for manual room selection in the booking flow.
|
|
*/
|
|
class RoomAssigner
|
|
{
|
|
/**
|
|
* Determines if automatic room assignment should be performed.
|
|
*
|
|
* Auto-assignment is only performed when exactly one room type is selected to avoid
|
|
* UX issues with individual participant forms. With multiple room types, users should
|
|
* manually select rooms to avoid having to unselect preassigned rooms.
|
|
*
|
|
* @param BookingDto $dto The booking DTO containing room selections
|
|
*
|
|
* @return bool True if auto-assignment should proceed, false otherwise
|
|
*/
|
|
public function shouldAutoAssignRooms(BookingDto $dto): bool
|
|
{
|
|
$selectedRoomTypeCount = 0;
|
|
|
|
foreach ($dto->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<int> Array of selected room IDs
|
|
*/
|
|
private function getSelectedRoomIds(BookingDto $dto): array
|
|
{
|
|
$ids = [];
|
|
foreach ($dto->getSelectedRooms() as $roomSelection) {
|
|
$ids[] = $roomSelection->id;
|
|
}
|
|
|
|
return $ids;
|
|
}
|
|
}
|