*/ final readonly class ProviderResourceDescriptor implements Arrayable, JsonSerializable { /** * @param array $sourceReferences */ public function __construct( public ResourceIdentity $identity, public ?string $displayLabel, public string $subjectDomain, public SubjectClass|string $subjectClass, public string $subjectTypeKey, public array $sourceReferences = [], public ?string $fingerprint = null, public ?string $lastSeenAt = null, ) {} /** * @param array $sourceReferences */ public static function fromIdentity( ResourceIdentity $identity, string $subjectDomain, SubjectClass|string $subjectClass, string $subjectTypeKey, ?string $displayLabel = null, array $sourceReferences = [], ?string $fingerprint = null, ?string $lastSeenAt = null, ): self { return new self( identity: $identity, displayLabel: $displayLabel, subjectDomain: $subjectDomain, subjectClass: $subjectClass, subjectTypeKey: $subjectTypeKey, sourceReferences: self::safeSourceReferences($sourceReferences), fingerprint: $fingerprint, lastSeenAt: $lastSeenAt, ); } /** * @param array $payload */ public static function fromArray(array $payload): self { $identityPayload = $payload['identity'] ?? []; return new self( identity: ResourceIdentity::fromArray(is_array($identityPayload) ? $identityPayload : []), displayLabel: self::nullableString($payload['display_label'] ?? null), subjectDomain: (string) ($payload['subject_domain'] ?? ''), subjectClass: (string) ($payload['subject_class'] ?? ''), subjectTypeKey: (string) ($payload['subject_type_key'] ?? ''), sourceReferences: self::safeSourceReferences(is_array($payload['source_references'] ?? null) ? $payload['source_references'] : []), fingerprint: self::nullableString($payload['fingerprint'] ?? null), lastSeenAt: self::nullableString($payload['last_seen_at'] ?? null), ); } /** * @return array{ * identity: array, * display_label: ?string, * subject_domain: string, * subject_class: string, * subject_type_key: string, * source_references: array, * fingerprint: ?string, * last_seen_at: ?string * } */ public function toArray(): array { return [ 'identity' => $this->identity->toArray(), 'display_label' => $this->displayLabel, 'subject_domain' => $this->subjectDomain, 'subject_class' => $this->subjectClass instanceof SubjectClass ? $this->subjectClass->value : $this->subjectClass, 'subject_type_key' => $this->subjectTypeKey, 'source_references' => self::safeSourceReferences($this->sourceReferences), 'fingerprint' => $this->fingerprint, 'last_seen_at' => $this->lastSeenAt, ]; } public function jsonSerialize(): array { return $this->toArray(); } /** * @param array $sourceReferences * @return array */ private static function safeSourceReferences(array $sourceReferences): array { $safe = []; foreach ($sourceReferences as $key => $value) { if (! is_string($key) || trim($key) === '' || (! is_scalar($value) && $value !== null)) { continue; } $safe[$key] = $value; } return $safe; } private static function nullableString(mixed $value): ?string { return is_string($value) && trim($value) !== '' ? trim($value) : null; } }