*/ private const CORE_CHANNELS = [ 'core.admin.dashboard', 'core.user.notifications.{uuid}', ]; public function __construct( private readonly ModuleManagerInterface $moduleManager, private readonly PluginManagerInterface $pluginManager, ) {} /** * 채널/이벤트 카탈로그를 수집합니다. * * @return array{channels: array, events: array} */ public function collect(): array { $channels = []; // 코어 채널. foreach (self::CORE_CHANNELS as $name) { $channels[] = ['name' => $name, 'source' => ['kind' => 'core']]; } // 모듈 채널. foreach ($this->moduleManager->getActiveModules() as $module) { foreach ($this->extractChannels($module) as $name) { $channels[] = [ 'name' => $name, 'source' => ['kind' => 'module', 'identifier' => $module->getIdentifier()], ]; } } // 플러그인 채널. foreach ($this->pluginManager->getActivePlugins() as $plugin) { foreach ($this->extractChannels($plugin) as $name) { $channels[] = [ 'name' => $name, 'source' => ['kind' => 'plugin', 'identifier' => $plugin->getIdentifier()], ]; } } return [ 'channels' => $channels, // 이벤트는 동적 발행이라 정적 카탈로그 없음 — 편집기 자유 텍스트 폴백. 'events' => [], ]; } /** * 확장의 `getChannels()` 에서 채널명 목록을 추출합니다(격리 호출). * * @param object $extension 확장 인스턴스 * @return array 채널명 목록 */ private function extractChannels(object $extension): array { if (! method_exists($extension, 'getChannels')) { return []; } try { $channels = $extension->getChannels(); } catch (\Throwable) { return []; } if (! is_array($channels)) { return []; } $names = []; foreach (array_keys($channels) as $name) { if (is_string($name) && $name !== '') { $names[] = $name; } } return $names; } }