$submittedData The submitted participant form data * @param string $mode The booking mode (BookingDto::MODE_CREATE or MODE_EDIT) * @param int $participantIndex The index of the participant being processed * * @return bool Always returns true for service selection fields */ public function shouldProcess(array $submittedData, string $mode, int $participantIndex): bool { return true; // Always process to handle deselection cases } public function processField(array $submittedData, BookingDto $bookingDto, int $participantIndex): void { $participant = $this->getParticipant($bookingDto, $participantIndex); if (null === $participant) { return; } // Store previous rental state BEFORE checking skipass $previousRentals = $participant->rentals; // Check if rentals should be available based on skipass selection if (null === $participant->skiPass) { // No skipass selected = clear all rental selections if ([] !== $previousRentals) { $participant->addNotification( 'warning', 'Ausrüstung wurde entfernt (kein Skipass ausgewählt)' ); } $participant->rentals = []; return; } $selectedRentals = $this->getFieldValue($submittedData, $this->getFieldName()) ?? []; // Get available rentals from travel data (includes booked rentals in edit mode) $availableRentals = $this->getAvailableServicesWithBooked( $bookingDto, $participantIndex, Constants::TOKEN_RENTALS, true ); // Filter rentals by skipass duration to ensure only matching rentals are available $durationFilteredRentals = $this->filterRentalsBySkiPassDuration($availableRentals, $participant); $validSelections = $this->filterValidServiceSelections( $selectedRentals, $durationFilteredRentals, $bookingDto, $participantIndex ); // Notify if rentals were cleared due to skipass duration change // Only show notification if user had submitted rentals that got filtered out, // not if the user intentionally cleared the selection (empty submission) if ([] !== $previousRentals && [] === $validSelections && [] !== $selectedRentals) { $participant->addNotification( 'warning', 'Ausrüstung wurde entfernt (andere Skipass-Dauer ausgewählt)' ); } $participant->rentals = $validSelections; } private function filterValidServiceSelections( array $selectedServices, array $availableServices, BookingDto $bookingDto, int $participantIndex, ): array { $validSelections = []; foreach ($selectedServices as $selectedService) { if ($this->isServiceValidForParticipant($selectedService, $availableServices, $bookingDto, $participantIndex)) { // Convert the selected service ID/data back to the actual Service object $serviceObject = $this->findServiceInAvailableServices($selectedService, $availableServices); if (null !== $serviceObject) { $validSelections[] = $serviceObject; } } } return $validSelections; } private function isServiceValidForParticipant( mixed $selectedService, array $availableServices, BookingDto $bookingDto, int $participantIndex, ): bool { $service = $this->findServiceInAvailableServices($selectedService, $availableServices); if (null === $service) { return false; } $ageEvaluator = new ServiceAgeEvaluator(); if (!$ageEvaluator->canEvaluate($service)) { return true; } return $ageEvaluator->isServiceAvailableForParticipant($service, $bookingDto, $participantIndex); } /** * Filters rentals to only include those matching the skipass duration. * * Rentals must have exact date matching with the selected skipass: * - rental.dateFrom === skipass.dateFrom * - rental.dateTo === skipass.dateTo * * @param array $rentals All available rental services * @param \App\Form\Model\ParticipantDto $participant The participant with skipass selection * * @return array Filtered rentals matching the skipass duration */ private function filterRentalsBySkiPassDuration(array $rentals, $participant): array { $selectedSkiPass = $participant->skiPass; // If skipass has no valid dates, return empty rentals if (null === $selectedSkiPass->dateFrom || null === $selectedSkiPass->dateTo) { return []; } return array_filter($rentals, function (Service $rental) use ($selectedSkiPass) { // Rental must have valid dates to be considered if (null === $rental->dateFrom || null === $rental->dateTo) { return false; } // Exact date matching: rental dates must match skipass dates exactly return $rental->dateFrom == $selectedSkiPass->dateFrom && $rental->dateTo == $selectedSkiPass->dateTo; }); } }