score = $score ?? new MergeScore(); } public function select(string $field, array $evidence, MergePolicy $policy): ?MergeEvidence { $evidence = array_values(array_filter($evidence, static fn ($item): bool => $item instanceof MergeEvidence)); if ($evidence === []) return null; $strategy = $policy->getStrategy($field); if ($strategy === self::MANUAL) { $manual = $policy->getManualValue($field); foreach ($evidence as $candidate) if ($candidate->getValue() === $manual) return $candidate; return $manual !== null ? new MergeEvidence($field, $manual, 'Manual', 1.0, 1.0) : null; } if ($strategy === self::PREFERRED_PROVIDER) { $preferred = strtolower((string) $policy->getPreferredProvider($field)); foreach ($evidence as $candidate) if (strtolower($candidate->getProvider()) === $preferred) return $candidate; } usort($evidence, function (MergeEvidence $left, MergeEvidence $right) use ($strategy): int { if ($strategy === self::LONGEST_DESCRIPTION) { $comparison = strlen((string) $right->getValue()) <=> strlen((string) $left->getValue()); } elseif ($strategy === self::NEWEST) { $comparison = ($right->getObservedAt()?->getTimestamp() ?? 0) <=> ($left->getObservedAt()?->getTimestamp() ?? 0); } elseif ($strategy === self::HIGHEST_CONFIDENCE) { $comparison = $this->score->confidence($right) <=> $this->score->confidence($left); } else { $comparison = $this->score->quality($right) <=> $this->score->quality($left); } return $comparison ?: ($this->score->combined($right) <=> $this->score->combined($left)) ?: strcasecmp($left->getProvider(), $right->getProvider()) ?: strcmp(serialize($left->getValue()), serialize($right->getValue())); }); return $evidence[0]; } }