wip: major refactoring
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user