From 43db14f0b1bf0aad720c4e4f0705ee85705d8d5e Mon Sep 17 00:00:00 2001 From: Nikolay Lobachev Date: Sun, 22 Apr 2018 21:02:07 +0200 Subject: [PATCH] [debug:hooks] Add command to display available in the system hooks. (#3790) * Add class HookCommand to display debug for hooks * Remove argument --- config/services/debug.yml | 5 + src/Command/Debug/HookCommand.php | 198 ++++++++++++++++++++++++++++++ 2 files changed, 203 insertions(+) create mode 100644 src/Command/Debug/HookCommand.php diff --git a/config/services/debug.yml b/config/services/debug.yml index 7d04fefff..5b546f80e 100644 --- a/config/services/debug.yml +++ b/config/services/debug.yml @@ -147,3 +147,8 @@ services: arguments: ['@console.drupal_api'] tags: - { name: drupal.command } + console.hook_debug: + class: Drupal\Console\Command\Debug\HookCommand + arguments: ['@console.extension_manager', '@module_handler'] + tags: + - { name: drupal.command } diff --git a/src/Command/Debug/HookCommand.php b/src/Command/Debug/HookCommand.php new file mode 100644 index 000000000..9e748704e --- /dev/null +++ b/src/Command/Debug/HookCommand.php @@ -0,0 +1,198 @@ +extensionManager = $extensionManager; + $this->moduleHandler = $moduleHandler; + parent::__construct(); + } + + /** + * {@inheritdoc} + */ + protected function configure() + { + $this + ->setName('debug:hook') + ->setDescription($this->trans('commands.debug.hook.description')) + ->setAliases(['dbh']); + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $this->findHooks(); + $tableHeader = [ + $this->trans('commands.debug.hook.messages.name'), + ]; + + $this->getIo()->table($tableHeader, $this->getHooks(), 'compact'); + return 0; + } + + protected function findHooks() + { + $modules = $this->getAllModules(); + $moduleInstances = []; + foreach ($modules as $module) { + $moduleInstance = $this->extensionManager->getModule($module); + if (empty($moduleInstance)) { + continue; + } + $moduleInstances[$module] = $moduleInstance; + $this->moduleHandler->setModuleList([$module => $moduleInstance]); + $this->findHooksInApiFile($moduleInstance); + + } + $this->getHooksFromHookInfo($moduleInstances); + } + + /** + * Get module of all modules in the system. + * + * @return array + * Module list. + */ + protected function getAllModules() + { + return $this->extensionManager->discoverModules() + ->showInstalled() + ->showUninstalled() + ->showNoCore() + ->showCore() + ->getList(true); + } + + /** + * Gets gooks from api file of the module. + * + * @param $moduleInstance + * Module instance. + */ + protected function findHooksInApiFile($moduleInstance) + { + $finder = new Finder(); + $files = $finder->files() + ->name("{$moduleInstance->info['name']}.api.php") + ->in($moduleInstance->getPath()); + + foreach ($files as $file) { + $functions = $this->getFileFunctions($file->getPathname()); + foreach ($functions as $function) { + if (Unicode::strpos($function, 'hook')) { + $this->addHook($function); + } + } + + } + } + + /** + * Get names of all functions from file. + * + * @param string $filePath + * File path + * @return array + * Functions list. + */ + protected function getFileFunctions($filePath) + { + $source = file_get_contents($filePath); + $tokens = token_get_all($source); + + $functions = []; + $nextStringIsFunc = false; + foreach($tokens as $token) { + switch($token[0]) { + case T_FUNCTION: + $nextStringIsFunc = true; + break; + + case T_STRING: + if ($nextStringIsFunc) { + $nextStringIsFunc = false; + $functions[] = $token[1]; + } + break; + } + } + + return $functions; + } + + /** + * @param $modules + */ + protected function getHooksFromHookInfo($modules) + { + $this->moduleHandler->setModuleList($modules); + foreach(array_keys($this->moduleHandler->getHookInfo()) as $hook) { + $this->addHook('hook_' . $hook); + } + } + + /** + * Add hook. + * + * @param string $value + * Hook name. + */ + protected function addHook($value) + { + $this->hooks[] = $value; + } + + protected function getHooks() + { + return $this->hooks; + } +}