$componentName]; foreach ($componentsByName[$componentName][KEY_COMPONENT_MODULES] as $module) { $component['modules'][] = $module; } $result[] = $component; } echo json_encode($result, JSON_PRETTY_PRINT); } elseif (isset($opt['list-component-dependencies'])) { //Get components that the specified component depends on, directly or indirectly $targetComponent = $opt['list-component-dependencies']; if (!isset($componentsByName[$targetComponent])) { die("Can't find specified component: " . $targetComponent . "\n"); } if ($directDependenciesOnly) { $dependencies = $componentsByName[$targetComponent][KEY_COMPONENT_DEPENDENCIES]; } else { $dependencies = getComponentDependency($targetComponent, KEY_COMPONENT_DEPENDENCIES); } echo json_encode($dependencies, JSON_PRETTY_PRINT); } elseif (isset($opt['list-component-dependents'])) { //Get components that depends on the specified component, directly or indirectly $targetComponent = $opt['list-component-dependents']; if (!isset($componentsByName[$targetComponent])) { die("Can't find specified component: " . $targetComponent . "\n"); } if ($directDependenciesOnly) { $dependencies = $componentsByName[$targetComponent][KEY_COMPONENT_DEPENDENTS]; } else { $dependencies = getComponentDependency($targetComponent, KEY_COMPONENT_DEPENDENTS); } echo json_encode($dependencies, JSON_PRETTY_PRINT); } elseif (isset($opt['list-module-dependents'])) { //Get modules that depends on the specified module, directly or indirectly $targetModule = $opt['list-module-dependents']; $dependencies = []; if (!isset($modules[$targetModule])) { die("Can't find specified module: " . $targetModule . "\n"); } if ($directDependenciesOnly) { foreach ($modules as $module) { if (in_array($targetModule, $module[KEY_MODULE_DEPENDENT_MODULES])) { $dependencies[] = $module[KEY_MODULE_NAME]; } } } else { $selfComponentName = $modules[$targetModule][KEY_MODULE_COMPONENT]; foreach ($componentsByName[$selfComponentName][KEY_COMPONENT_MODULES] as $module) { if ($module != $targetModule) { $dependencies[] = $module; } } $componentDependencies = getComponentDependency( $selfComponentName, KEY_COMPONENT_DEPENDENTS ); foreach ($componentDependencies as $component) { foreach ($componentsByName[$component][KEY_COMPONENT_MODULES] as $module) { if (!in_array($module, $dependencies)) { $dependencies[] = $module; } } } } echo json_encode($dependencies, JSON_PRETTY_PRINT); } elseif (isset($opt['list-module-dependencies'])) { //Get modules that depends on the specified module, directly or indirectly $targetModule = $opt['list-module-dependencies']; $dependencies = []; if (!isset($modules[$targetModule])) { die("Can't find specified module: " . $targetModule . "\n"); } if ($directDependenciesOnly) { $module = $modules[$targetModule]; $dependencies = $module[KEY_MODULE_DEPENDENT_MODULES]; } else { $selfComponentName = $modules[$targetModule][KEY_MODULE_COMPONENT]; foreach ($componentsByName[$selfComponentName][KEY_COMPONENT_MODULES] as $module) { if ($module != $targetModule) { $dependencies[] = $module; } } $componentDependencies = getComponentDependency( $selfComponentName, KEY_COMPONENT_DEPENDENCIES ); foreach ($componentDependencies as $component) { foreach ($componentsByName[$component][KEY_COMPONENT_MODULES] as $module) { if (!in_array($module, $dependencies)) { $dependencies[] = $module; } } } } echo json_encode($dependencies, JSON_PRETTY_PRINT); } /** * For a given component, return a list of components that depend on the component or a list of components * that the given component depends on * * @param string $component * @param string $direction * @return array */ function getComponentDependency($component, $direction) { global $componentsByName; $dependencies = []; $queue = []; foreach ($componentsByName[$component][$direction] as $componentName) { $dependencies[] = $componentName; $queue[] = $componentName; } while (!empty($queue)) { $head = array_shift($queue); $headComponent = $componentsByName[$head]; foreach ($headComponent[$direction] as $componentName) { if (!in_array($componentName, $dependencies)) { $dependencies[] = $componentName; $queue[] = $componentName; } } } return $dependencies; } /** * initialize the component and module dependency * * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) * @return void */ function initialize() { global $modules, $componentsByName; $baseDir = "../../"; $fileNames = glob($baseDir . "app/code/Magento/*/composer.json"); foreach ($fileNames as $fileName) { $moduleDirectoryName = basename(dirname($fileName)); $content = json_decode(file_get_contents($fileName), true); if ($content[KEY_COMPOSER_COMPONENT_TYPE] != KEY_COMPOSER_MAGENTO2_MODULE) { continue; } $dependentModules = []; $dependencies = $content[KEY_COMPOSER_REQUIRE]; foreach (array_keys($dependencies) as $name) { $dependentModules[$name] = $name; } $moduleName = $content[KEY_COMPOSER_COMPONENT_NAME]; $modules[$moduleName] = [ KEY_MODULE_DIRECTORY_NAME => $moduleDirectoryName, KEY_MODULE_DEPENDENT_MODULES => $dependentModules, KEY_MODULE_NAME => $moduleName, ]; } //going through the array one more time to clean up the content, remove the dependencies that are not module foreach ($modules as &$module) { $dependentModules = []; foreach ($module[KEY_MODULE_DEPENDENT_MODULES] as $dependentModuleName) { if (isset($modules[$dependentModuleName])) { $dependentModules[$dependentModuleName] = $dependentModuleName; } } $module[KEY_MODULE_DEPENDENT_MODULES] = $dependentModules; } //Group strongly connected modules as components $components = identifyComponents($modules); foreach ($components as &$component) { if (count($component[KEY_COMPONENT_MODULES]) == 1) { $component[KEY_COMPONENT_NAME] = $component[KEY_COMPONENT_MODULES][0]; $modules[$component[KEY_COMPONENT_MODULES][0]][KEY_MODULE_COMPONENT] = $component[KEY_COMPONENT_NAME]; } else { $component[KEY_COMPONENT_NAME] = implode(':', $component[KEY_COMPONENT_MODULES]); } foreach ($component[KEY_COMPONENT_MODULES] as $moduleName) { $modules[$moduleName][KEY_MODULE_COMPONENT] = $component[KEY_COMPONENT_NAME]; } $componentsByName[$component[KEY_COMPONENT_NAME]] = $component; } //Process dependency between components foreach ($componentsByName as $name => &$component) { foreach ($component[KEY_COMPONENT_MODULES] as $moduleName) { foreach ($modules[$moduleName][KEY_MODULE_DEPENDENT_MODULES] as $dependentModule) { $dependentComponent = $modules[$dependentModule][KEY_MODULE_COMPONENT]; if ($dependentComponent != $component[KEY_COMPONENT_NAME]) { $component[KEY_COMPONENT_DEPENDENCIES][$dependentComponent] = $dependentComponent; $componentsByName[$dependentComponent][KEY_COMPONENT_DEPENDENTS][$component[KEY_COMPONENT_NAME]] = $component[KEY_COMPONENT_NAME]; } } } } foreach ($componentsByName as &$component) { if (!isset($component[KEY_COMPONENT_DEPENDENTS])) { $component[KEY_COMPONENT_DEPENDENTS] = []; } if (!isset($component[KEY_COMPONENT_DEPENDENCIES])) { $component[KEY_COMPONENT_DEPENDENCIES] = []; } } } /** * For a given acyclic graph of components, sort the components according to the dependencies so that components * can only depend on components with lower index * * @param array $components * @return array */ function topologicalSort($components) { $sortedComponents = []; $rootComponents = []; foreach ($components as $component) { if (empty($component[KEY_COMPONENT_DEPENDENCIES])) { $rootComponents[] = $component; } } while (!empty($rootComponents)) { $rootComponent = array_shift($rootComponents); $sortedComponents[] = $rootComponent[KEY_COMPONENT_NAME]; foreach ($rootComponent[KEY_COMPONENT_DEPENDENTS] as $componentName) { unset($components[$componentName][KEY_COMPONENT_DEPENDENCIES][$rootComponent[KEY_COMPONENT_NAME]]); if (empty($components[$componentName][KEY_COMPONENT_DEPENDENCIES])) { $rootComponents[] = $components[$componentName]; } } } return $sortedComponents; } /** * Identify components in the dependency graph using Tarjan algorithm. Modules that circularly depend on each other * are grouped into components. Modules that are not in a cyclic graph are grouped into component of its own * * @param array $modules * @return array */ function identifyComponents($modules) { $index = 0; $stack = []; $components = []; foreach ($modules as &$module) { if (!isset($module['index'])) { identifyComponent($modules, $module, $stack, $index, $components); } } return $components; } /** * Recursive function to identify one component * * @param array $modules * @param array $module * @param array $stack * @param int $index * @param array $components * @return void */ function identifyComponent(&$modules, &$module, &$stack, &$index, &$components) { $module['index'] = $index; $module['lowlink'] = $index; $index++; $stack[] = $module[KEY_MODULE_NAME]; foreach ($module[KEY_MODULE_DEPENDENT_MODULES] as $dependentModuleName) { $dependentModule = &$modules[$dependentModuleName]; if (!isset($dependentModule['index'])) { identifyComponent($modules, $dependentModule, $stack, $index, $components); $module['lowlink'] = min($module['lowlink'], $dependentModule['lowlink']); } elseif (in_array($dependentModuleName, $stack)) { $module['lowlink'] = min($module['lowlink'], $dependentModule['index']); } } if ($module['lowlink'] == $module['index']) { $component = []; do { $moduleName = array_pop($stack); $component[KEY_COMPONENT_MODULES][] = $moduleName; } while ($moduleName != $module[KEY_MODULE_NAME]); $components[] = $component; } }