diff --git a/modules/system/classes/PluginManager.php b/modules/system/classes/PluginManager.php index a92ea6490..0985f2c32 100644 --- a/modules/system/classes/PluginManager.php +++ b/modules/system/classes/PluginManager.php @@ -11,7 +11,7 @@ use Config; use Schema; use RecursiveIteratorIterator; use RecursiveDirectoryIterator; -use ApplicationException; +use SystemException; /** * Plugin manager @@ -108,6 +108,8 @@ class PluginManager $this->loadPlugin($namespace, $path); } + $this->sortDependencies(); + return $this->plugins; } @@ -674,43 +676,25 @@ class PluginManager } } - /** - * Returns the plugin identifiers that are required by the supplied plugin. - * @param string $plugin Plugin identifier, object or class - * @return array - */ - public function getDependencies($plugin) - { - if (is_string($plugin) && (!$plugin = $this->findByIdentifier($plugin))) { - return false; - } - - if (!isset($plugin->require) || !$plugin->require) { - return null; - } - - return is_array($plugin->require) ? $plugin->require : [$plugin->require]; - } - /** * Sorts a collection of plugins, in the order that they should be actioned, * according to their given dependencies. Least dependent come first. - * @param array $plugins Object collection to sort, or null to sort all. * @return array Collection of sorted plugin identifiers */ - public function sortByDependencies($plugins = null) + protected function sortDependencies() { - if (!is_array($plugins)) { - $plugins = $this->getPlugins(); - } + ksort($this->plugins); + /* + * Canvas the dependency tree + */ + $checklist = $this->plugins; $result = []; - $checklist = $plugins; $loopCount = 0; while (count($checklist)) { - if (++$loopCount > 999) { - throw new ApplicationException('Too much recursion'); + if (++$loopCount > 2048) { + throw new SystemException('Too much recursion! Check for circular dependencies in your plugins.'); } foreach ($checklist as $code => $plugin) { @@ -718,8 +702,8 @@ class PluginManager * Get dependencies and remove any aliens */ $depends = $this->getDependencies($plugin) ?: []; - $depends = array_filter($depends, function ($pluginCode) use ($plugins) { - return isset($plugins[$pluginCode]); + $depends = array_filter($depends, function ($pluginCode) { + return isset($this->plugins[$pluginCode]); }); /* @@ -746,7 +730,46 @@ class PluginManager unset($checklist[$code]); } } - return $result; + + /* + * Reassemble plugin map + */ + $sortedPlugins = []; + + foreach ($result as $code) { + $sortedPlugins[$code] = $this->plugins[$code]; + } + + return $this->plugins = $sortedPlugins; + } + + /** + * Returns the plugin identifiers that are required by the supplied plugin. + * @param string $plugin Plugin identifier, object or class + * @return array + */ + public function getDependencies($plugin) + { + if (is_string($plugin) && (!$plugin = $this->findByIdentifier($plugin))) { + return false; + } + + if (!isset($plugin->require) || !$plugin->require) { + return null; + } + + return is_array($plugin->require) ? $plugin->require : [$plugin->require]; + } + + /** + * @deprecated Plugins are now sorted by default. See getPlugins() + * Remove if year >= 2022 + */ + public function sortByDependencies($plugins = null) + { + traceLog('PluginManager::sortByDependencies is deprecated. Plugins are now sorted by default. Use PluginManager::getPlugins()'); + + return array_keys($plugins ?: $this->getPlugins()); } // diff --git a/modules/system/classes/UpdateManager.php b/modules/system/classes/UpdateManager.php index 0f8264199..53ba96468 100644 --- a/modules/system/classes/UpdateManager.php +++ b/modules/system/classes/UpdateManager.php @@ -149,9 +149,9 @@ class UpdateManager /* * Update plugins */ - $plugins = $this->pluginManager->sortByDependencies(); - foreach ($plugins as $plugin) { - $this->updatePlugin($plugin); + $plugins = $this->pluginManager->getPlugins(); + foreach ($plugins as $code => $plugin) { + $this->updatePlugin($code); } Parameter::set('system::update.count', 0);