diff options
Diffstat (limited to 'core/Application/Kernel/PluginList.php')
-rw-r--r-- | core/Application/Kernel/PluginList.php | 75 |
1 files changed, 73 insertions, 2 deletions
diff --git a/core/Application/Kernel/PluginList.php b/core/Application/Kernel/PluginList.php index 5d263a6ea3..70abc543d5 100644 --- a/core/Application/Kernel/PluginList.php +++ b/core/Application/Kernel/PluginList.php @@ -8,6 +8,8 @@ namespace Piwik\Application\Kernel; +use Piwik\Plugin\MetadataLoader; + /** * Lists the currently activated plugins. Used when setting up Piwik's environment before * initializing the DI container. @@ -88,7 +90,8 @@ class PluginList } /** - * Sorts an array of plugins in the order they should be loaded. + * Sorts an array of plugins in the order they should be loaded. We cannot use DI here as DI is not initialized + * at this stage. * * @params string[] $plugins * @return \string[] @@ -111,10 +114,78 @@ class PluginList $otherPluginsToLoadAfterDefaultPlugins = array_diff($plugins, $defaultPluginsLoadedFirst); // sort by name to have a predictable order for those extra plugins - sort($otherPluginsToLoadAfterDefaultPlugins); + natcasesort($otherPluginsToLoadAfterDefaultPlugins); $sorted = array_merge($defaultPluginsLoadedFirst, $otherPluginsToLoadAfterDefaultPlugins); return $sorted; } + + /** + * Sorts an array of plugins in the order they should be saved in config.ini.php. This basically influences + * the order of the plugin config.php and which config will be loaded first. We want to make sure to require the + * config or a required plugin first before loading the plugin that requires it. + * + * We do not sort using this logic on each request since it is much slower than `sortPlugins()`. The order + * of plugins in config.ini.php is only important for the ContainerFactory. During a regular request it is otherwise + * fine to load the plugins in the order of `sortPlugins()` since we will make sure that required plugins will be + * loaded first in plugin manager. + * + * @param string[] $plugins + * @param array[] $pluginJsonCache For internal testing only + * @return \string[] + */ + public function sortPluginsAndRespectDependencies(array $plugins, $pluginJsonCache = array()) + { + $global = $this->getPluginsBundledWithPiwik(); + + if (empty($global)) { + return $plugins; + } + + // we need to make sure a possibly disabled plugin will be still loaded before any 3rd party plugin + $global = array_merge($global, $this->corePluginsDisabledByDefault); + + $global = array_values($global); + $plugins = array_values($plugins); + + $defaultPluginsLoadedFirst = array_intersect($global, $plugins); + + $otherPluginsToLoadAfterDefaultPlugins = array_diff($plugins, $defaultPluginsLoadedFirst); + + // we still want to sort alphabetically by default + natcasesort($otherPluginsToLoadAfterDefaultPlugins); + + $sorted = array(); + foreach ($otherPluginsToLoadAfterDefaultPlugins as $pluginName) { + $sorted = $this->sortRequiredPlugin($pluginName, $pluginJsonCache, $otherPluginsToLoadAfterDefaultPlugins, $sorted); + } + + $sorted = array_merge($defaultPluginsLoadedFirst, $sorted); + + return $sorted; + } + + private function sortRequiredPlugin($pluginName, &$pluginJsonCache, $toBeSorted, $sorted) + { + if (!isset($pluginJsonCache[$pluginName])) { + $loader = new MetadataLoader($pluginName); + $pluginJsonCache[$pluginName] = $loader->loadPluginInfoJson(); + } + + if (!empty($pluginJsonCache[$pluginName]['require'])) { + $dependencies = $pluginJsonCache[$pluginName]['require']; + foreach ($dependencies as $possiblePluginName => $key) { + if (in_array($possiblePluginName, $toBeSorted, true) && !in_array($possiblePluginName, $sorted, true)) { + $sorted = $this->sortRequiredPlugin($possiblePluginName, $pluginJsonCache, $toBeSorted, $sorted); + } + } + } + + if (!in_array($pluginName, $sorted, true)) { + $sorted[] = $pluginName; + } + + return $sorted; + } } |