addParser(new BirthYearConstraintParser()); } public function addParser(AgeConstraintParserInterface $parser): void { $this->parsers[] = $parser; } public function parseConstraints(string $constraintData): AgeConstraintResult { // Handle multiple constraint types (semicolon-separated, e.g., 'JG:2007-2009;GL:5-8') $constraints = array_map('trim', explode(';', $constraintData)); $results = []; foreach ($constraints as $constraint) { if (empty($constraint)) { continue; } foreach ($this->parsers as $parser) { if (true === $parser->canParse($constraint)) { $results[] = $parser->parse($constraint); break; // First matching parser wins } } } // Merge results if multiple constraints found return $this->mergeConstraintResults($results, $constraintData); } private function mergeConstraintResults(array $results, string $rawData): AgeConstraintResult { if (empty($results)) { return new AgeConstraintResult(type: 'unknown', rawData: $rawData); } if (1 === count($results)) { return $results[0]; } // Merge multiple constraint results $type = 'mixed'; $ageFrom = null; $ageTo = null; $birthYearFrom = null; $birthYearTo = null; $metadata = ['merged_from' => []]; foreach ($results as $result) { $ageFrom = $this->mergeMinValue($ageFrom, $result->ageFrom); $ageTo = $this->mergeMaxValue($ageTo, $result->ageTo); $birthYearFrom = $this->mergeMinValue($birthYearFrom, $result->birthYearFrom); $birthYearTo = $this->mergeMaxValue($birthYearTo, $result->birthYearTo); $metadata['merged_from'][] = $result->type; } return new AgeConstraintResult( type: $type, ageFrom: $ageFrom, ageTo: $ageTo, birthYearFrom: $birthYearFrom, birthYearTo: $birthYearTo, metadata: $metadata, rawData: $rawData ); } private function mergeMinValue(?int $current, ?int $new): ?int { if (null === $current) { return $new; } if (null === $new) { return $current; } return max($current, $new); // Most restrictive minimum } private function mergeMaxValue(?int $current, ?int $new): ?int { if (null === $current) { return $new; } if (null === $new) { return $current; } return min($current, $new); // Most restrictive maximum } }