*/ private readonly array $providers; public function __construct( ContentEvidenceProvider $contentEvidenceProvider, MetaEvidenceProvider $metaEvidenceProvider, ) { $this->providers = [ $contentEvidenceProvider, $metaEvidenceProvider, ]; } /** * Resolve best-available current-state evidence per subject using the ordered provider chain. * * First-non-null wins. * * @param list $subjects * @return array keyed by "policy_type|subject_external_id" */ public function resolveForSubjects( Tenant $tenant, array $subjects, ?CarbonImmutable $since = null, ?int $latestInventorySyncRunId = null, ): array { $results = []; $unresolved = []; foreach ($subjects as $subject) { $policyType = trim((string) ($subject['policy_type'] ?? '')); $externalId = trim((string) ($subject['subject_external_id'] ?? '')); if ($policyType === '' || $externalId === '') { continue; } $key = $policyType.'|'.$externalId; if (array_key_exists($key, $results)) { continue; } $results[$key] = null; $unresolved[$key] = [ 'policy_type' => $policyType, 'subject_external_id' => $externalId, ]; } foreach ($this->providers as $provider) { if ($unresolved === []) { break; } $resolved = $provider->resolve( tenant: $tenant, subjects: array_values($unresolved), since: $since, latestInventorySyncRunId: $latestInventorySyncRunId, ); foreach ($resolved as $key => $evidence) { if (! array_key_exists($key, $unresolved)) { continue; } $results[$key] = $evidence; unset($unresolved[$key]); } } return $results; } }