'', // The title of the help topic plugin. 'label' => '', // Whether or not the topic should appear on the help topics list. 'top_level' => '', // List of related topic machine names. 'related' => [], // The class used to instantiate the plugin. 'class' => '', ]; /** * Constructs a new HelpTopicManager object. * * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler * The module handler. * @param \Drupal\Core\Extension\ThemeHandlerInterface $themeHandler * The theme handler. * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend * Cache backend instance to use. * @param string $root * The app root. */ public function __construct(ModuleHandlerInterface $module_handler, protected ThemeHandlerInterface $themeHandler, CacheBackendInterface $cache_backend, protected string $root) { // Note that the parent construct is not called because this class does not // use annotated class discovery. $this->moduleHandler = $module_handler; $this->alterInfo('help_topics_info'); $this->setCacheBackend($cache_backend, 'help_topics'); } /** * {@inheritdoc} */ protected function getDiscovery() { if (!isset($this->discovery)) { $module_directories = $this->moduleHandler->getModuleDirectories(); $all_directories = array_merge( ['core' => $this->root . '/core'], $module_directories, $this->themeHandler->getThemeDirectories() ); // Search for Twig help topics in subdirectory help_topics, under // modules/profiles, themes, and the core directory. $all_directories = array_map(function ($dir) { return [$dir . '/help_topics']; }, $all_directories); $discovery = new HelpTopicDiscovery($all_directories); // Also allow modules/profiles to extend help topic discovery to their // own plugins and derivers, in my_module.help_topics.yml files. $discovery = new YamlDiscoveryDecorator($discovery, 'help_topics', $module_directories); $discovery = new ContainerDerivativeDiscoveryDecorator($discovery); $this->discovery = $discovery; } return $this->discovery; } /** * {@inheritdoc} */ protected function providerExists($provider) { return $this->moduleHandler->moduleExists($provider) || $this->themeHandler->themeExists($provider); } /** * {@inheritdoc} */ protected function findDefinitions() { $definitions = parent::findDefinitions(); // At this point the plugin list only contains valid plugins. Ensure all // related plugins exist and the relationship is bi-directional. This // ensures topics are listed on their related topics. foreach ($definitions as $plugin_id => $plugin_definition) { foreach ($plugin_definition['related'] as $key => $related_id) { // If the related help topic does not exist it might be for a module // that is not installed. Remove it. // @todo Discuss this more as this could cause silent errors but it // offers useful functionality to relate to a help topic provided by // extensions that are yet to be installed. // https://www.drupal.org/i/3360133 if (!isset($definitions[$related_id])) { unset($definitions[$plugin_id]['related'][$key]); continue; } // Make the related relationship bi-directional. if (isset($definitions[$related_id]) && !in_array($plugin_id, $definitions[$related_id]['related'], TRUE)) { $definitions[$related_id]['related'][] = $plugin_id; } } } return $definitions; } }