$contextualIdentityDetails */ public function __construct( public readonly string $provider, public readonly ProviderConnectionTargetScopeDescriptor $targetScope, public readonly string $consentState, public readonly string $verificationState, public readonly string $readinessSummary, public readonly array $contextualIdentityDetails = [], public readonly bool $isEnabled = true, public readonly array $providerCapabilities = [], public readonly ?array $primaryProviderCapability = null, ) {} public static function forConnection(ProviderConnection $connection): self { /** @var ProviderConnectionTargetScopeNormalizer $normalizer */ $normalizer = app(ProviderConnectionTargetScopeNormalizer::class); $targetScope = $normalizer->descriptorForConnection($connection); $consentState = self::stateValue($connection->consent_status); $verificationState = self::stateValue($connection->verification_status); $providerCapabilities = self::providerCapabilitiesForConnection($connection); $primaryProviderCapability = self::primaryProviderCapability($providerCapabilities); return new self( provider: trim((string) $connection->provider), targetScope: $targetScope, consentState: $consentState, verificationState: $verificationState, readinessSummary: self::readinessSummary( isEnabled: (bool) $connection->is_enabled, consentState: $consentState, verificationState: $verificationState, ), contextualIdentityDetails: $normalizer->contextualIdentityDetailsForConnection($connection), isEnabled: (bool) $connection->is_enabled, providerCapabilities: $providerCapabilities, primaryProviderCapability: $primaryProviderCapability, ); } public function targetScopeSummary(): string { return $this->targetScope->summary(); } public function contextualIdentityLine(): ?string { if ($this->contextualIdentityDetails === []) { return null; } return collect($this->contextualIdentityDetails) ->map(fn (ProviderIdentityContextMetadata $detail): string => sprintf('%s: %s', $detail->detailLabel, $detail->detailValue)) ->implode("\n"); } public function providerCapabilitySummary(): string { if (! is_array($this->primaryProviderCapability)) { return 'Provider capabilities not evaluated'; } $label = (string) ($this->primaryProviderCapability['label'] ?? 'Provider capability'); $status = (string) ($this->primaryProviderCapability['status'] ?? 'unknown'); $statusLabel = BadgeRenderer::spec(BadgeDomain::ProviderCapabilityStatus, $status)->label; return "{$label}: {$statusLabel}"; } /** * @return array{ * provider: string, * target_scope: array, * consent_state: string, * verification_state: string, * readiness_summary: string, * target_scope_summary: string, * provider_context: array{provider: string, details: list>}, * contextual_identity_line: ?string, * is_enabled: bool, * provider_capabilities: array>, * primary_provider_capability: ?array, * provider_capability_summary: string * } */ public function toArray(): array { return [ 'provider' => $this->provider, 'target_scope' => $this->targetScope->toArray(), 'consent_state' => $this->consentState, 'verification_state' => $this->verificationState, 'readiness_summary' => $this->readinessSummary, 'target_scope_summary' => $this->targetScopeSummary(), 'provider_context' => $this->providerContext(), 'contextual_identity_line' => $this->contextualIdentityLine(), 'is_enabled' => $this->isEnabled, 'provider_capabilities' => $this->providerCapabilities, 'primary_provider_capability' => $this->primaryProviderCapability, 'provider_capability_summary' => $this->providerCapabilitySummary(), ]; } /** * @return array{provider: string, details: list>} */ public function providerContext(): array { return [ 'provider' => $this->provider, 'details' => array_map( static fn (ProviderIdentityContextMetadata $detail): array => $detail->toArray(), $this->contextualIdentityDetails, ), ]; } private static function stateValue(mixed $state): string { if ($state instanceof ProviderConsentStatus || $state instanceof ProviderVerificationStatus) { return $state->value; } return trim((string) $state); } private static function readinessSummary(bool $isEnabled, string $consentState, string $verificationState): string { if (! $isEnabled) { return 'Disabled'; } if ($consentState !== ProviderConsentStatus::Granted->value) { return sprintf( 'Consent %s', strtolower(BadgeRenderer::spec(BadgeDomain::ProviderConsentStatus, $consentState)->label), ); } return match ($verificationState) { ProviderVerificationStatus::Healthy->value => 'Ready', ProviderVerificationStatus::Degraded->value => 'Ready with warnings', ProviderVerificationStatus::Blocked->value => 'Verification blocked', ProviderVerificationStatus::Error->value => 'Verification failed', ProviderVerificationStatus::Pending->value => 'Verification pending', default => 'Verification not run', }; } /** * @return array> */ private static function providerCapabilitiesForConnection(ProviderConnection $connection): array { try { /** @var ProviderCapabilityEvaluator $evaluator */ $evaluator = app(ProviderCapabilityEvaluator::class); return array_map( static fn (ProviderCapabilityResult $result): array => $result->toArray(), $evaluator->evaluateForConnection($connection), ); } catch (\Throwable) { return []; } } /** * @param array> $capabilities * @return array|null */ private static function primaryProviderCapability(array $capabilities): ?array { if ($capabilities === []) { return null; } usort($capabilities, static function (array $a, array $b): int { $aStatus = (string) ($a['status'] ?? 'unknown'); $bStatus = (string) ($b['status'] ?? 'unknown'); $aPriority = match ($aStatus) { 'blocked' => 0, 'missing' => 1, 'unknown' => 2, 'supported' => 3, default => 4, }; $bPriority = match ($bStatus) { 'blocked' => 0, 'missing' => 1, 'unknown' => 2, 'supported' => 3, default => 4, }; return $aPriority <=> $bPriority; }); return $capabilities[0]; } }