*/ private array $bodyDimensionRanges; /** * @param array $bodyDimensionRanges */ public function __construct( array $bodyDimensionRanges, ) { $this->bodyDimensionRanges = $this->resolveOptions($bodyDimensionRanges); } public function ensureParticipantExists(BookingDto $bookingDto, int $index): ParticipantDto { $participant = $bookingDto->participants[$index] ?? null; if (null === $participant) { throw new ParticipantNotFoundException($index); } return $participant; } /** * Builds the traveller that stays behind at index 0 when the applicant stops travelling. * * Only the booking-structural fields carry over. Everything service-shaped was derived from * the applicant's age and no longer applies to whoever actually travels in that slot. */ public function createBlankTravellerFrom(ParticipantDto $previous): ParticipantDto { $traveller = new ParticipantDto(); $traveller->index = 0; $traveller->assignedRoomId = $previous->assignedRoomId; return $traveller; } /** * Drops a family insurance selection from every participant. * * Used when a booking turns into a split booking, where family insurance is not offered. */ public function clearFamilyInsurance(BookingDto $bookingDto): void { foreach ($bookingDto->participants as $participant) { if (true === $participant->insurance?->familyInsurance) { $participant->insurance = null; } $participant->bulkInsuranceBooking = false; } } public function createParticipantEditDto(BookingDto $bookingDto, int $index): ParticipantEditDto { return new ParticipantEditDto( participant: $this->ensureParticipantExists($bookingDto, $index), bookingContext: $bookingDto, ); } /** * @return array */ public function getParticipantFormOptions(BookingDto $bookingDto, bool $disableValidation = false): array { $options = [ 'booking_context' => $bookingDto, 'body_dimension_ranges' => $this->bodyDimensionRanges, ]; if (true === $disableValidation) { $options['validation_groups'] = false; } return $options; } /** * Collects participant notifications and clears them from the DTO. * * @return array */ public function collectAndClearNotifications(BookingDto $bookingDto): array { $notifications = []; foreach ($bookingDto->participants as $participant) { if (false === empty($participant->notifications)) { $notifications = array_merge($notifications, $participant->notifications); $participant->notifications = []; } } return array_values($notifications); } /** * @param array $options * * @return array */ private function resolveOptions(array $options): array { $optionsResolver = new OptionsResolver(); $optionsResolver->setRequired([ 'height_min', 'height_max', 'weight_min', 'weight_max', 'shoe_size_min', 'shoe_size_max', ]); $optionsResolver->setAllowedTypes('height_min', ['int']); $optionsResolver->setAllowedTypes('height_max', ['int']); $optionsResolver->setAllowedTypes('weight_min', ['int']); $optionsResolver->setAllowedTypes('weight_max', ['int']); $optionsResolver->setAllowedTypes('shoe_size_min', ['int']); $optionsResolver->setAllowedTypes('shoe_size_max', ['int']); return $optionsResolver->resolve($options); } }