$maxAge) { throw new \InvalidArgumentException('Minimum age cannot be greater than maximum age'); } } /** * Evaluates if the participant's age meets the specified criteria. * * Calculates the participant's current age from their date of birth and * checks if it falls within the configured age range. Returns false if * the participant has no date of birth set. * * @param BookingDtoInterface $bookingDto The current booking data (create or edit) * @param int $participantIndex The index of the participant being evaluated * @param array $formData Current form data (unused for age conditions) * * @return bool True if the participant's age meets the criteria, false otherwise */ public function evaluate(BookingDtoInterface $bookingDto, int $participantIndex, array $formData): bool { $participant = $bookingDto->getParticipant($participantIndex); if (null === $participant || null === $participant->dateOfBirth) { return false; } $age = $this->calculateAge($participant->dateOfBirth); // Check minimum age requirement if (null !== $this->minAge && $age < $this->minAge) { return false; } // Check maximum age requirement if (null !== $this->maxAge && $age > $this->maxAge) { return false; } return true; } /** * Returns field names that affect age calculation. * * The age condition depends on the participant's date of birth field. * When this field changes, any conditions based on age should be re-evaluated. * * @return string[] Array containing 'dateOfBirth' field name */ public function getDependentFields(): array { return ['dateOfBirth']; } /** * Returns a human-readable description of the age criteria. * * Generates a descriptive string explaining the age requirements, * useful for debugging and understanding condition logic. * * @return string Description of the age range criteria */ public function getDescription(): string { if (null !== $this->minAge && null !== $this->maxAge) { if ($this->minAge === $this->maxAge) { return sprintf('Participant must be exactly %d years old', $this->minAge); } return sprintf('Participant must be between %d and %d years old', $this->minAge, $this->maxAge); } if (null !== $this->minAge) { return sprintf('Participant must be at least %d years old', $this->minAge); } return sprintf('Participant must be under %d years old', $this->maxAge + 1); } /** * Calculates age in years from a date of birth. * * Uses DateTimeImmutable to ensure immutable date calculations and * handles the calculation accurately accounting for leap years and * exact birth date anniversaries. * * @param \DateTimeImmutable $dateOfBirth The participant's date of birth * * @return int The calculated age in complete years */ private function calculateAge(\DateTimeImmutable $dateOfBirth): int { $today = new \DateTimeImmutable(); return (int) $dateOfBirth->diff($today)->y; } }