$allowedContexts * @param list $legacyAliases * @param list $forbiddenPlatformAliases */ public function __construct( public string $termKey, public string $canonicalLabel, public string $canonicalDescription, public string $boundaryClassification, public string $ownerLayer, public array $allowedContexts = [], public array $legacyAliases = [], public ?string $aliasRetirementPath = null, public array $forbiddenPlatformAliases = [], ) { if (trim($this->termKey) === '' || trim($this->canonicalLabel) === '' || trim($this->canonicalDescription) === '') { throw new InvalidArgumentException('Platform vocabulary terms require a key, label, and description.'); } if ($this->legacyAliases !== [] && blank($this->aliasRetirementPath)) { throw new InvalidArgumentException('Platform vocabulary terms with legacy aliases must declare an alias retirement path.'); } } /** * @param array $data */ public static function fromArray(array $data): self { return new self( termKey: (string) ($data['term_key'] ?? ''), canonicalLabel: (string) ($data['canonical_label'] ?? ''), canonicalDescription: (string) ($data['canonical_description'] ?? ''), boundaryClassification: (string) ($data['boundary_classification'] ?? ''), ownerLayer: (string) ($data['owner_layer'] ?? ''), allowedContexts: self::stringList($data['allowed_contexts'] ?? []), legacyAliases: self::stringList($data['legacy_aliases'] ?? []), aliasRetirementPath: is_string($data['alias_retirement_path'] ?? null) ? trim((string) $data['alias_retirement_path']) : null, forbiddenPlatformAliases: self::stringList($data['forbidden_platform_aliases'] ?? []), ); } public function matches(string $term): bool { $normalized = trim(mb_strtolower($term)); if ($normalized === '') { return false; } return in_array($normalized, array_map( static fn (string $candidate): string => trim(mb_strtolower($candidate)), array_merge([$this->termKey], $this->legacyAliases), ), true); } /** * @return array{ * term_key: string, * canonical_label: string, * canonical_description: string, * boundary_classification: string, * owner_layer: string, * allowed_contexts: list, * legacy_aliases: list, * alias_retirement_path: ?string, * forbidden_platform_aliases: list * } */ public function toArray(): array { return [ 'term_key' => $this->termKey, 'canonical_label' => $this->canonicalLabel, 'canonical_description' => $this->canonicalDescription, 'boundary_classification' => $this->boundaryClassification, 'owner_layer' => $this->ownerLayer, 'allowed_contexts' => $this->allowedContexts, 'legacy_aliases' => $this->legacyAliases, 'alias_retirement_path' => $this->aliasRetirementPath, 'forbidden_platform_aliases' => $this->forbiddenPlatformAliases, ]; } /** * @param iterable $values * @return list */ private static function stringList(iterable $values): array { return collect($values) ->filter(static fn (mixed $value): bool => is_string($value) && trim($value) !== '') ->map(static fn (string $value): string => trim($value)) ->values() ->all(); } }