diff --git a/config/services.yaml b/config/services.yaml index d6135aa..bab7a49 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -64,10 +64,6 @@ services: $cache: '@cache.app' $logger: '@monolog.logger.bpn' - App\Form\Service\Factory\ParticipantRoomChoiceLoaderFactory: - arguments: - $choiceListFactory: '@form.choice_list_factory.default' - # Field Handlers with dependencies App\Form\Service\ParticipantInsuranceFieldHandler: ~ App\Form\Service\ParticipantBulkInsuranceFieldHandler: ~ diff --git a/src/Form/ChoiceLoader/ParticipantRoomChoiceLoader.php b/src/Form/ChoiceLoader/ParticipantRoomChoiceLoader.php deleted file mode 100644 index f6a1a6a..0000000 --- a/src/Form/ChoiceLoader/ParticipantRoomChoiceLoader.php +++ /dev/null @@ -1,80 +0,0 @@ -choiceList) { - $choices = $this->generateRoomChoicesForParticipant(); - $this->choiceList = $this->factory->createListFromChoices($choices, $value); - } - - return $this->choiceList; - } - - public function loadChoicesForValues(array $values, ?callable $value = null): array - { - if (empty($values)) { - return []; - } - - return $this->loadChoiceList($value)->getChoicesForValues($values); - } - - public function loadValuesForChoices(array $choices, ?callable $value = null): array - { - if (empty($choices)) { - return []; - } - - return $this->loadChoiceList($value)->getValuesForChoices($choices); - } - - /** - * Generates room choices for the specific participant. - * - * Always includes all selected rooms from Step 1 regardless of current capacity. - * Capacity conflicts are handled by the field handler during assignment. - * - * @return array - */ - private function generateRoomChoicesForParticipant(): array - { - $participantRoomChoices = []; - - foreach ($this->selectedRooms as $roomSelection) { - // Always include all selected rooms - capacity conflicts handled in field handler - $participantRoomChoices[$roomSelection->roomLabel] = $roomSelection->roomId; - } - - return $participantRoomChoices; - } -} diff --git a/src/Form/Service/Factory/ParticipantRoomChoiceLoaderFactory.php b/src/Form/Service/Factory/ParticipantRoomChoiceLoaderFactory.php deleted file mode 100644 index 8009dcd..0000000 --- a/src/Form/Service/Factory/ParticipantRoomChoiceLoaderFactory.php +++ /dev/null @@ -1,91 +0,0 @@ -choiceListFactory, - $selectedRooms - ); - } - - /** - * Creates a ParticipantRoomChoiceLoader for edit context. - * - * Uses already-booked rooms from the existing booking to generate available - * room choices. Participants can only be reassigned within the room types - * that have already been booked. - * - * @param Room[] $bookedRooms rooms from the existing booking - */ - public function createForEdit(array $bookedRooms): ParticipantRoomChoiceLoader - { - // Convert Booking Room objects to RoomSelectionDto format for the choice loader - $roomSelections = $this->convertBookedRoomsToSelections($bookedRooms); - - return new ParticipantRoomChoiceLoader( - $this->choiceListFactory, - $roomSelections - ); - } - - /** - * Converts booked Room objects to RoomSelectionDto format. - * - * This adapter method allows reusing the existing ParticipantRoomChoiceLoader - * logic for edit context by converting the Booking->rooms array into the - * same format used in the create flow. - * - * @param Room[] $bookedRooms rooms from existing booking - * - * @return RoomSelectionDto[] converted room selections - */ - private function convertBookedRoomsToSelections(array $bookedRooms): array - { - $selections = []; - - foreach ($bookedRooms as $room) { - $selection = new RoomSelectionDto(); - $selection->roomId = $room->id; - $selection->roomLabel = $room->label; - $selection->roomPrice = $room->price; - // In edit context, totalCount represents how many of this room type were booked - $selection->quantity = $room->totalCount ?? 1; - // maxPax is the capacity per room - $selection->capacity = $room->maxPax ?? 1; - - $selections[] = $selection; - } - - return $selections; - } -} diff --git a/src/Form/Service/ParticipantFieldOptionsProvider.php b/src/Form/Service/ParticipantFieldOptionsProvider.php index 35de9c6..ca26966 100644 --- a/src/Form/Service/ParticipantFieldOptionsProvider.php +++ b/src/Form/Service/ParticipantFieldOptionsProvider.php @@ -7,12 +7,12 @@ namespace App\Form\Service; use App\BusProNet\Constants; use App\BusProNet\Model\Insurance; use App\BusProNet\Model\Pickup; +use App\BusProNet\Model\Room; use App\BusProNet\Model\Service; use App\BusProNet\Utility\DirectionMapper; use App\Form\Model\BookingDto; use App\Form\Model\RoomSelectionDto; use App\Form\Service\Abstract\AbstractFieldOptionsProvider; -use App\Form\Service\Factory\ParticipantRoomChoiceLoaderFactory; use App\Service\BookingPriceCalculatorService; use App\Service\InsuranceService; use App\Service\ServiceAvailabilityCalculator; @@ -36,21 +36,7 @@ use App\Service\ServiceAvailabilityCalculator; */ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider { - /** - * Initializes the provider with required dependencies. - * - * The provider automatically registers all field option providers during - * construction to ensure they're available for form building. This approach - * keeps all field configuration logic centralized and makes it easy to add - * new dynamic fields. - * - * @param ParticipantRoomChoiceLoaderFactory $roomChoiceLoaderFactory Factory for creating room choice loaders - * @param ServiceAvailabilityCalculator $serviceAvailabilityCalculator Service for calculating dynamic availability - * @param InsuranceService $insuranceService Service for insurance operations - * @param BookingPriceCalculatorService $priceCalculatorService Service for calculating participant prices - */ public function __construct( - private readonly ParticipantRoomChoiceLoaderFactory $roomChoiceLoaderFactory, private readonly ServiceAvailabilityCalculator $serviceAvailabilityCalculator, private readonly InsuranceService $insuranceService, private readonly BookingPriceCalculatorService $priceCalculatorService, @@ -83,8 +69,7 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider { // Room assignment field provider (available for both create and edit workflows) $this->fieldOptionProviders['assignedRoomId'] = function (BookingDto $bookingDto, int $participantIndex, array $options = []) { - $choiceLoader = null; - $singleChoice = false; + $choices = []; if (BookingDto::MODE_CREATE === $bookingDto->getMode()) { // Create context: use selected rooms from step 1, filtered by participant age @@ -93,26 +78,19 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider $bookingDto, $participantIndex ); - $choiceLoader = $this->roomChoiceLoaderFactory->createForCreate($filteredRooms); - $singleChoice = 1 === count($filteredRooms); + $choices = $this->buildRoomChoicesFromSelections($filteredRooms); } elseif (BookingDto::MODE_EDIT === $bookingDto->getMode()) { // Edit context: use already-booked rooms from booking - $choiceLoader = $this->roomChoiceLoaderFactory->createForEdit( - $bookingDto->booking->rooms - ); - $singleChoice = 1 === count($bookingDto->booking->rooms); + $choices = $this->buildRoomChoicesFromBookedRooms($bookingDto->booking->rooms); } + $singleChoice = 1 === count($choices); + return [ 'label' => 'Zimmer', // No placeholder when only one room available - the only option is pre-selected 'placeholder' => $singleChoice ? false : 'Nicht zugeordnet', - // Use factory to create context-aware choice loader that: - // - Shows only available rooms for this participant - // - Excludes rooms already assigned to other participants - // - Respects room capacity and booking constraints - // - Filters Baby rooms for participants over 2 years old - 'choice_loader' => $choiceLoader, + 'choices' => $choices, ]; }; @@ -548,6 +526,40 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider }); } + /** + * Builds room choices array from RoomSelectionDto objects. + * + * @param RoomSelectionDto[] $roomSelections Room selections from step 1 + * + * @return array Choices array with label => id + */ + private function buildRoomChoicesFromSelections(array $roomSelections): array + { + $choices = []; + foreach ($roomSelections as $roomSelection) { + $choices[$roomSelection->roomLabel] = $roomSelection->roomId; + } + + return $choices; + } + + /** + * Builds room choices array from booked Room objects. + * + * @param Room[] $bookedRooms Rooms from existing booking + * + * @return array Choices array with label => id + */ + private function buildRoomChoicesFromBookedRooms(array $bookedRooms): array + { + $choices = []; + foreach ($bookedRooms as $room) { + $choices[$room->label] = $room->id; + } + + return $choices; + } + /** * Filters rental services by selected skipass duration. * diff --git a/tests/Form/Service/ParticipantFieldOptionsProviderBabyTest.php b/tests/Form/Service/ParticipantFieldOptionsProviderBabyTest.php index e9f6577..ab5eaf4 100644 --- a/tests/Form/Service/ParticipantFieldOptionsProviderBabyTest.php +++ b/tests/Form/Service/ParticipantFieldOptionsProviderBabyTest.php @@ -10,7 +10,6 @@ use App\BusProNet\Model\Travel; use App\BusProNet\Utility\DirectionMapper; use App\Form\Model\BookingDto; use App\Form\Model\ParticipantDto; -use App\Form\Service\Factory\ParticipantRoomChoiceLoaderFactory; use App\Form\Service\ParticipantFieldOptionsProvider; use App\Service\BookingPriceCalculatorService; use App\Service\InsuranceService; @@ -24,13 +23,11 @@ class ParticipantFieldOptionsProviderBabyTest extends TestCase protected function setUp(): void { - $roomChoiceLoaderFactory = $this->createMock(ParticipantRoomChoiceLoaderFactory::class); $this->serviceAvailabilityCalculator = $this->createMock(ServiceAvailabilityCalculator::class); $insuranceService = $this->createMock(InsuranceService::class); $priceCalculatorService = $this->createMock(BookingPriceCalculatorService::class); $this->provider = new ParticipantFieldOptionsProvider( - $roomChoiceLoaderFactory, $this->serviceAvailabilityCalculator, $insuranceService, $priceCalculatorService