*/ private array $integrations; /** @var list}>|null Available integrations with their abilities. */ private ?array $loaded = null; private bool $booted = false; private ?Compatibility $compatibility = null; public function __construct(Integration ...$integrations) { $this->integrations = array_values($integrations); } /** * Boots every Bootable integration once, in registry order – available or not: Plugin boots on plugins_loaded, * before the theme (Divi) is loaded, so isAvailable() is not known yet (as the hooks were registered before * Bootable). A second call does nothing. */ public function boot(): void { if ($this->booted) { return; } $this->booted = true; foreach ($this->integrations as $integration) { if ($integration instanceof Bootable) { $integration->boot(); } } } /** @return list */ public function available(): array { return array_values(array_filter( $this->integrations, static fn (Integration $integration): bool => $integration->isAvailable() )); } /** @return list */ public function abilities(): array { $abilities = []; foreach ($this->loaded() as [, $own]) { array_push($abilities, ...$own); } return $abilities; } /** * Abilities of the available integrations, grouped by integration id (registry order). An integration without * abilities (Pods) is no group. * * @return array> */ public function grouped(): array { $groups = []; foreach ($this->loaded() as [$integration, $own]) { if ($own === []) { continue; } $groups[$integration->id()] = array_merge($groups[$integration->id()] ?? [], $own); } return $groups; } /** @return array Ability name => integration id (the ability's group). */ public function groupMap(): array { $map = []; foreach ($this->grouped() as $id => $abilities) { foreach ($abilities as $ability) { $map[$ability->name()] = $id; } } return $map; } /** @return array Integration id => label, of the available integrations. */ public function labels(): array { $labels = []; foreach ($this->loaded() as [$integration]) { $labels[$integration->id()] = $integration->label(); } return $labels; } /** @return list Profiles of every registered integration that provides some, available or not. */ public function compatibilities(): array { $profiles = []; foreach ($this->integrations as $integration) { if ($integration instanceof ProvidesCompatibility) { array_push($profiles, ...$integration->compatibilities()); } } return $profiles; } /** * The compatibility state of all profiles, one shared instance (its matrices are memoised per request). * * @throws LogicException When two profiles or capabilities share an ID (a programming error, PluginTest). */ public function compatibility(): Compatibility { return $this->compatibility ??= new Compatibility($this->compatibilities()); } /** @return list Ids of all known integrations, available or not. */ public function ids(): array { return array_values(array_unique(array_map( static fn (Integration $integration): string => $integration->id(), $this->integrations ))); } /** @return list}> */ private function loaded(): array { if ($this->loaded === null) { $this->loaded = array_map( static fn (Integration $integration): array => [$integration, $integration->abilities()], $this->available() ); } return $this->loaded; } }