TenantAtlas/apps/platform/app/Support/Governance/RegistryOwnershipDescriptor.php
2026-04-14 08:07:40 +02:00

87 lines
3.0 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Support\Governance;
use InvalidArgumentException;
final readonly class RegistryOwnershipDescriptor
{
/**
* @param list<string> $canonicalNouns
* @param list<string> $allowedConsumers
*/
public function __construct(
public string $registryKey,
public string $boundaryClassification,
public string $ownerLayer,
public string $sourceClassOrFile,
public array $canonicalNouns,
public array $allowedConsumers,
public ?string $compatibilityNotes = null,
) {
if (trim($this->registryKey) === '' || trim($this->sourceClassOrFile) === '') {
throw new InvalidArgumentException('Registry ownership descriptors require a registry key and source reference.');
}
if ($this->canonicalNouns === [] || $this->allowedConsumers === []) {
throw new InvalidArgumentException('Registry ownership descriptors require canonical nouns and allowed consumers.');
}
}
/**
* @param array<string, mixed> $data
*/
public static function fromArray(array $data): self
{
return new self(
registryKey: (string) ($data['registry_key'] ?? ''),
boundaryClassification: (string) ($data['boundary_classification'] ?? ''),
ownerLayer: (string) ($data['owner_layer'] ?? ''),
sourceClassOrFile: (string) ($data['source_class_or_file'] ?? ''),
canonicalNouns: self::stringList($data['canonical_nouns'] ?? []),
allowedConsumers: self::stringList($data['allowed_consumers'] ?? []),
compatibilityNotes: is_string($data['compatibility_notes'] ?? null)
? trim((string) $data['compatibility_notes'])
: null,
);
}
/**
* @return array{
* registry_key: string,
* boundary_classification: string,
* owner_layer: string,
* source_class_or_file: string,
* canonical_nouns: list<string>,
* allowed_consumers: list<string>,
* compatibility_notes: ?string
* }
*/
public function toArray(): array
{
return [
'registry_key' => $this->registryKey,
'boundary_classification' => $this->boundaryClassification,
'owner_layer' => $this->ownerLayer,
'source_class_or_file' => $this->sourceClassOrFile,
'canonical_nouns' => $this->canonicalNouns,
'allowed_consumers' => $this->allowedConsumers,
'compatibility_notes' => $this->compatibilityNotes,
];
}
/**
* @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();
}
}