Integrations name their own admin group (Integration::label, registry labels()); ToolsTab no longer hard-codes ids and explains why it re-applies withGroups. AccessTab and LogTab share AdminPostAction (guard, redirect, terminate seam). ExposurePolicy parses option keys in one place, has one isRequired() check and a clear $groups docblock (null vs []). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
103 lines
2.7 KiB
PHP
103 lines
2.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace LIT\MCP\Integrations;
|
|
|
|
use LIT\MCP\Abilities\Ability;
|
|
|
|
final class IntegrationRegistry
|
|
{
|
|
/** @var list<Integration> */
|
|
private array $integrations;
|
|
|
|
/** @var list<array{Integration, list<Ability>}>|null Available integrations with their abilities. */
|
|
private ?array $loaded = null;
|
|
|
|
public function __construct(Integration ...$integrations)
|
|
{
|
|
$this->integrations = array_values($integrations);
|
|
}
|
|
|
|
/** @return list<Integration> */
|
|
public function available(): array
|
|
{
|
|
return array_values(array_filter(
|
|
$this->integrations,
|
|
static fn (Integration $integration): bool => $integration->isAvailable()
|
|
));
|
|
}
|
|
|
|
/** @return list<Ability> */
|
|
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).
|
|
*
|
|
* @return array<string, list<Ability>>
|
|
*/
|
|
public function grouped(): array
|
|
{
|
|
$groups = [];
|
|
foreach ($this->loaded() as [$integration, $own]) {
|
|
$groups[$integration->id()] = array_merge($groups[$integration->id()] ?? [], $own);
|
|
}
|
|
|
|
return $groups;
|
|
}
|
|
|
|
/** @return array<string, string> 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<string, string> 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<string> 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<array{Integration, list<Ability>}> */
|
|
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;
|
|
}
|
|
}
|