110 lines
3.9 KiB
PHP
110 lines
3.9 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Support\Governance;
|
|
|
|
use InvalidArgumentException;
|
|
|
|
final readonly class PlatformVocabularyTerm
|
|
{
|
|
/**
|
|
* @param list<string> $allowedContexts
|
|
* @param list<string> $legacyAliases
|
|
* @param list<string> $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<string, mixed> $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<string>,
|
|
* legacy_aliases: list<string>,
|
|
* alias_retirement_path: ?string,
|
|
* forbidden_platform_aliases: list<string>
|
|
* }
|
|
*/
|
|
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<mixed> $values
|
|
* @return list<string>
|
|
*/
|
|
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();
|
|
}
|
|
} |