142 lines
4.9 KiB
PHP
142 lines
4.9 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Form\Service\Condition;
|
|
|
|
use App\Form\Model\BookingDtoInterface;
|
|
use App\Form\Service\Contract\FieldConditionInterface;
|
|
|
|
/**
|
|
* Condition that evaluates participant age against specified range criteria.
|
|
*
|
|
* This condition checks if a participant's age (calculated from their date of birth)
|
|
* falls within, outside, or meets specific age criteria. It's commonly used to
|
|
* enable/disable fields based on age restrictions for services, legal requirements,
|
|
* or business rules.
|
|
*
|
|
* Age Calculation:
|
|
* - Uses participant's dateOfBirth property to calculate current age
|
|
* - Handles null dates gracefully (condition fails if no birth date)
|
|
* - Age is calculated as of today's date when condition is evaluated
|
|
*
|
|
* Range Types:
|
|
* - Minimum age: participant must be at least X years old
|
|
* - Maximum age: participant must be under X years old
|
|
* - Age range: participant must be between X and Y years old
|
|
* - Exact age: participant must be exactly X years old
|
|
*/
|
|
class AgeRangeCondition implements FieldConditionInterface
|
|
{
|
|
/**
|
|
* Creates a new age range condition.
|
|
*
|
|
* @param int|null $minAge Minimum required age (inclusive), null for no minimum
|
|
* @param int|null $maxAge Maximum allowed age (inclusive), null for no maximum
|
|
*/
|
|
public function __construct(
|
|
private readonly ?int $minAge = null,
|
|
private readonly ?int $maxAge = null,
|
|
) {
|
|
if (null === $minAge && null === $maxAge) {
|
|
throw new \InvalidArgumentException('At least one of minAge or maxAge must be specified');
|
|
}
|
|
|
|
if (null !== $minAge && null !== $maxAge && $minAge > $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<string, mixed> $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;
|
|
}
|
|
}
|