*/ private readonly array $disabled; /** * @param list|string|null $disabled keys this installation * has been told it may not * use; a comma-separated * string is what the * environment supplies */ public function __construct( private readonly Edition $edition, array|string|null $disabled = [], ) { // Parsed here rather than read from config(), so the registry stays // a value object that can be constructed with nothing but its two // facts -- which is what lets it be unit-tested without booting an // application, and what stops the edition and the subtraction being // read from two different places at two different times. $this->disabled = is_array($disabled) ? $disabled : array_values(array_filter( array_map(trim(...), explode(',', (string) $disabled)), fn (string $key): bool => $key !== '', )); } public function edition(): Edition { return $this->edition; } public function has(Capability $capability): bool { return $capability->availableIn($this->edition) && ! in_array($capability->value, $this->disabled, true); } /** * @return list */ public function enabled(): array { return array_values(array_filter( Capability::cases(), fn (Capability $capability): bool => $this->has($capability), )); } /** * Capability keys enabled for this edition, for Inertia shared props and * API responses. * * @return list */ public function enabledKeys(): array { return array_map( fn (Capability $capability): string => $capability->value, $this->enabled(), ); } }