fix: properly assign readonly state to form fields for unavailable services

This commit is contained in:
Björn Fromme
2026-03-16 12:00:56 +01:00
parent 96619c6cec
commit 3984a623bf
14 changed files with 68 additions and 140 deletions
@@ -104,10 +104,7 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
'expanded' => true,
'required' => false,
'choices' => $this->filterServicesByAgeConstraints(
$bookingDto->travel->getAdditionalServicesBySubTypes(
Constants::TOKEN_COURSES,
BookingDto::MODE_CREATE === $bookingDto->getMode() // Only filter by availability in create mode
),
$bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_COURSES),
$bookingDto,
$participantIndex
),
@@ -142,10 +139,7 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
'expanded' => true,
'required' => false,
'choices' => $this->filterServicesByAgeConstraints(
$bookingDto->travel->getAdditionalServicesBySubTypes(
Constants::TOKEN_ADDITIONAL,
BookingDto::MODE_EDIT !== $bookingDto->getMode() // Only filter by availability in create mode
),
$bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_ADDITIONAL),
$bookingDto,
$participantIndex
),
@@ -188,10 +182,7 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
'expanded' => true,
'required' => false,
'choices' => $this->filterServicesByAgeConstraints(
$bookingDto->travel->getAdditionalServicesBySubTypes(
Constants::TOKEN_BOARD,
BookingDto::MODE_CREATE === $bookingDto->getMode() // Only filter by availability in create mode
),
$bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_BOARD),
$bookingDto,
$participantIndex
),
@@ -227,11 +218,7 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
'required' => false,
'choices' => $this->filterServicesByAgeConstraints(
$this->filterRentalsBySkiPassDuration(
$bookingDto->travel->getAdditionalServicesBySubTypes(
Constants::TOKEN_RENTALS,
BookingDto::MODE_CREATE === $bookingDto->getMode(), // Only filter by availability in create mode
true // Filter by travel date range
),
$bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_RENTALS, true),
$bookingDto,
$participantIndex
),
@@ -264,10 +251,10 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
// Rental insurance field provider - provides rental insurance options when rental services are selected
$this->fieldOptionProviders['rentalInsurance'] = fn (BookingDto $bookingDto, int $participantIndex, array $options = []) => [
'label' => $this->getRentalInsuranceCheckboxLabel($bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_RENTAL_INSURANCE, true, true)),
'label' => $this->getRentalInsuranceCheckboxLabel($bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_RENTAL_INSURANCE, true)),
'required' => false,
'property_path' => 'rentalInsuranceSelected',
'help' => $this->getRentalInsuranceDescription($bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_RENTAL_INSURANCE, true, true)),
'help' => $this->getRentalInsuranceDescription($bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_RENTAL_INSURANCE, true)),
];
// License plate field provider - provides text input for vehicle license plate when parking is selected
@@ -292,11 +279,7 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
'expanded' => true,
'required' => true,
'choices' => $this->filterServicesByAgeConstraints(
$bookingDto->travel->getAdditionalServicesBySubTypes(
Constants::TOKEN_SKI_PASS,
BookingDto::MODE_CREATE === $bookingDto->getMode(), // Only filter by availability in create mode
true // Filter by travel date range
),
$bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_SKI_PASS, true),
$bookingDto,
$participantIndex
),
@@ -340,7 +323,7 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
$this->fieldOptionProviders['transportationOutbound'] = fn (BookingDto $bookingDto, int $participantIndex, array $options = []) => [
'label' => 'Hinfahrt',
'choices' => $this->filterTransportationChoices(
$bookingDto->travel->getTransportationServicesByDirection(DirectionMapper::OUTBOUND_TRAVEL, false),
$bookingDto->travel->getTransportationServicesByDirection(DirectionMapper::OUTBOUND_TRAVEL),
$bookingDto,
$participantIndex
),
@@ -374,7 +357,7 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
// Inbound Transportation
$this->fieldOptionProviders['transportationInbound'] = fn (BookingDto $bookingDto, int $participantIndex, array $options = []) => [
'label' => 'Rückfahrt',
'choices' => $bookingDto->travel->getTransportationServicesByDirection(DirectionMapper::INBOUND_TRAVEL, false),
'choices' => $bookingDto->travel->getTransportationServicesByDirection(DirectionMapper::INBOUND_TRAVEL),
'choice_label' => fn (Service $service) => $service?->label,
'choice_value' => 'id',
'expanded' => true,
@@ -417,7 +400,7 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
// Parking (conditional - only shown when outbound transportation is PKW)
// Simple checkbox since there's only ever one parking type
$this->fieldOptionProviders['parking'] = fn (BookingDto $bookingDto, int $participantIndex, array $options = []) => [
'label' => $this->getParkingCheckboxLabel($bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_PARKING, true)),
'label' => $this->getParkingCheckboxLabel($bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_PARKING)),
'required' => false,
];
@@ -118,7 +118,7 @@ class ParticipantParkingFieldHandler extends AbstractParticipantFieldHandler
*/
private function findParkingService(BookingDto $bookingDto): ?Service
{
$parkingServices = $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_PARKING, true);
$parkingServices = $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_PARKING);
if (empty($parkingServices)) {
return null;
@@ -125,7 +125,7 @@ class ParticipantRentalInsuranceFieldHandler extends AbstractParticipantFieldHan
*/
private function findRentalInsuranceService(BookingDto $bookingDto): ?Service
{
$rentalInsuranceServices = $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_RENTAL_INSURANCE, true, true);
$rentalInsuranceServices = $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_RENTAL_INSURANCE, true);
if (empty($rentalInsuranceServices)) {
return null;
@@ -83,7 +83,7 @@ class ParticipantRentalsFieldHandler extends AbstractParticipantFieldHandler
}
$selectedRentals = $this->getFieldValue($submittedData, $this->getFieldName()) ?? [];
$availableRentals = $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_RENTALS, true, true);
$availableRentals = $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_RENTALS, true);
// Filter rentals by skipass duration to ensure only matching rentals are available
$durationFilteredRentals = $this->filterRentalsBySkiPassDuration($availableRentals, $participant);
@@ -94,8 +94,8 @@ class ParticipantSkiPassFieldHandler extends AbstractParticipantFieldHandler
// Extract current skipass selection from submitted data
$selectedSkiPass = $this->getFieldValue($submittedData, $this->getFieldName());
// Get available skipasses from travel data (with date filtering)
$availableSkipasses = $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_SKI_PASS, true, true);
// Get all skipasses from travel data (with date filtering)
$availableSkipasses = $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_SKI_PASS, true);
// For single selection, validate the selected skipass and convert ID to Service object
$validSelection = null;
@@ -62,10 +62,8 @@ class ParticipantTransportationDiscountReplacementFieldHandler extends AbstractP
&& DirectionMapper::SUBTYPE_BUS_API === $participant->transportationInbound->subType;
// Step 3: Get all outbound PKW services
// Get ALL outbound services (not filtered by availability or smart filtering)
$allOutboundServices = $bookingDto->travel->getTransportationServicesByDirection(
DirectionMapper::OUTBOUND_TRAVEL,
false // Do NOT filter by per-booking availability
DirectionMapper::OUTBOUND_TRAVEL
);
// Find discounted and regular PKW services
@@ -50,13 +50,12 @@ class ParticipantTransportationInboundFieldHandler extends AbstractParticipantFi
$selectedTransportation = $this->getFieldValue($submittedData, $this->getFieldName());
// Get available inbound transportation services
$availableServices = $bookingDto->travel->getTransportationServicesByDirection(
DirectionMapper::INBOUND_TRAVEL,
true // filter available
// Get all inbound transportation services (availability filtering happens at form level)
$services = $bookingDto->travel->getTransportationServicesByDirection(
DirectionMapper::INBOUND_TRAVEL
);
// Validate and update participant with selection
$participant->transportationInbound = $this->findItemById($selectedTransportation, $availableServices);
$participant->transportationInbound = $this->findItemById($selectedTransportation, $services);
}
}
@@ -50,13 +50,12 @@ class ParticipantTransportationOutboundFieldHandler extends AbstractParticipantF
$selectedTransportation = $this->getFieldValue($submittedData, $this->getFieldName());
// Get available outbound transportation services
$availableServices = $bookingDto->travel->getTransportationServicesByDirection(
DirectionMapper::OUTBOUND_TRAVEL,
true // filter available
// Get all outbound transportation services (availability filtering happens at form level)
$services = $bookingDto->travel->getTransportationServicesByDirection(
DirectionMapper::OUTBOUND_TRAVEL
);
// Validate and update participant with selection
$participant->transportationOutbound = $this->findItemById($selectedTransportation, $availableServices);
$participant->transportationOutbound = $this->findItemById($selectedTransportation, $services);
}
}