PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 4.3.0
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v4.3.0
5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / app / core / Application / Kernel / PluginList.php
matomo / app / core / Application / Kernel Last commit date
EnvironmentValidator.php 5 years ago GlobalSettingsProvider.php 5 years ago PluginList.php 5 years ago
PluginList.php
197 lines
1 <?php
2 /**
3 * Matomo - free/libre analytics platform
4 *
5 * @link https://matomo.org
6 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
7 */
8
9 namespace Piwik\Application\Kernel;
10
11 use Piwik\Plugin\MetadataLoader;
12
13 /**
14 * Lists the currently activated plugins. Used when setting up Piwik's environment before
15 * initializing the DI container.
16 *
17 * Uses the [Plugins] section in Piwik's INI config to get the activated plugins.
18 *
19 * Depends on GlobalSettingsProvider being used.
20 *
21 * TODO: parts of Plugin\Manager edit the plugin list; maybe PluginList implementations should be mutable?
22 */
23 class PluginList
24 {
25 /**
26 * @var GlobalSettingsProvider
27 */
28 private $settings;
29
30 /**
31 * Plugins bundled with core package, disabled by default
32 * @var array
33 */
34 private $corePluginsDisabledByDefault = array(
35 'DBStats',
36 'ExamplePlugin',
37 'ExampleCommand',
38 'ExampleSettingsPlugin',
39 'ExampleUI',
40 'ExampleVisualization',
41 'ExamplePluginTemplate',
42 'ExampleTracker',
43 'ExampleLogTables',
44 'ExampleReport',
45 'ExampleAPI',
46 'MobileAppMeasurable',
47 'TagManager'
48 );
49
50 // Themes bundled with core package, disabled by default
51 private $coreThemesDisabledByDefault = array(
52 'ExampleTheme'
53 );
54
55 public function __construct(GlobalSettingsProvider $settings)
56 {
57 $this->settings = $settings;
58 }
59
60 /**
61 * Returns the list of plugins that should be loaded. Used by the container factory to
62 * load plugin specific DI overrides.
63 *
64 * @return string[]
65 */
66 public function getActivatedPlugins()
67 {
68 $section = $this->settings->getSection('Plugins');
69 $plugins = @$section['Plugins'] ?: array();
70
71 return $plugins;
72 }
73
74 /**
75 * Returns the list of plugins that are bundled with Piwik.
76 *
77 * @return string[]
78 */
79 public function getPluginsBundledWithPiwik()
80 {
81 $pathGlobal = $this->settings->getPathGlobal();
82
83 $section = $this->settings->getIniFileChain()->getFrom($pathGlobal, 'Plugins');
84 return $section['Plugins'];
85 }
86
87 /**
88 * Returns the plugins bundled with core package that are disabled by default.
89 *
90 * @return string[]
91 */
92 public function getCorePluginsDisabledByDefault()
93 {
94 return array_merge($this->corePluginsDisabledByDefault, $this->coreThemesDisabledByDefault);
95 }
96
97 /**
98 * Sorts an array of plugins in the order they should be loaded. We cannot use DI here as DI is not initialized
99 * at this stage.
100 *
101 * @params string[] $plugins
102 * @return \string[]
103 */
104 public function sortPlugins(array $plugins)
105 {
106 $global = $this->getPluginsBundledWithPiwik();
107 if (empty($global)) {
108 return $plugins;
109 }
110
111 // we need to make sure a possibly disabled plugin will be still loaded before any 3rd party plugin
112 $global = array_merge($global, $this->corePluginsDisabledByDefault);
113
114 $global = array_values($global);
115 $plugins = array_values($plugins);
116
117 $defaultPluginsLoadedFirst = array_intersect($global, $plugins);
118
119 $otherPluginsToLoadAfterDefaultPlugins = array_diff($plugins, $defaultPluginsLoadedFirst);
120
121 // sort by name to have a predictable order for those extra plugins
122 natcasesort($otherPluginsToLoadAfterDefaultPlugins);
123
124 $sorted = array_merge($defaultPluginsLoadedFirst, $otherPluginsToLoadAfterDefaultPlugins);
125
126 return $sorted;
127 }
128
129 /**
130 * Sorts an array of plugins in the order they should be saved in config.ini.php. This basically influences
131 * the order of the plugin config.php and which config will be loaded first. We want to make sure to require the
132 * config or a required plugin first before loading the plugin that requires it.
133 *
134 * We do not sort using this logic on each request since it is much slower than `sortPlugins()`. The order
135 * of plugins in config.ini.php is only important for the ContainerFactory. During a regular request it is otherwise
136 * fine to load the plugins in the order of `sortPlugins()` since we will make sure that required plugins will be
137 * loaded first in plugin manager.
138 *
139 * @param string[] $plugins
140 * @param array[] $pluginJsonCache For internal testing only
141 * @return \string[]
142 */
143 public function sortPluginsAndRespectDependencies(array $plugins, $pluginJsonCache = array())
144 {
145 $global = $this->getPluginsBundledWithPiwik();
146
147 if (empty($global)) {
148 return $plugins;
149 }
150
151 // we need to make sure a possibly disabled plugin will be still loaded before any 3rd party plugin
152 $global = array_merge($global, $this->corePluginsDisabledByDefault);
153
154 $global = array_values($global);
155 $plugins = array_values($plugins);
156
157 $defaultPluginsLoadedFirst = array_intersect($global, $plugins);
158
159 $otherPluginsToLoadAfterDefaultPlugins = array_diff($plugins, $defaultPluginsLoadedFirst);
160
161 // we still want to sort alphabetically by default
162 natcasesort($otherPluginsToLoadAfterDefaultPlugins);
163
164 $sorted = array();
165 foreach ($otherPluginsToLoadAfterDefaultPlugins as $pluginName) {
166 $sorted = $this->sortRequiredPlugin($pluginName, $pluginJsonCache, $otherPluginsToLoadAfterDefaultPlugins, $sorted);
167 }
168
169 $sorted = array_merge($defaultPluginsLoadedFirst, $sorted);
170
171 return $sorted;
172 }
173
174 private function sortRequiredPlugin($pluginName, &$pluginJsonCache, $toBeSorted, $sorted)
175 {
176 if (!isset($pluginJsonCache[$pluginName])) {
177 $loader = new MetadataLoader($pluginName);
178 $pluginJsonCache[$pluginName] = $loader->loadPluginInfoJson();
179 }
180
181 if (!empty($pluginJsonCache[$pluginName]['require'])) {
182 $dependencies = $pluginJsonCache[$pluginName]['require'];
183 foreach ($dependencies as $possiblePluginName => $key) {
184 if (in_array($possiblePluginName, $toBeSorted, true) && !in_array($possiblePluginName, $sorted, true)) {
185 $sorted = $this->sortRequiredPlugin($possiblePluginName, $pluginJsonCache, $toBeSorted, $sorted);
186 }
187 }
188 }
189
190 if (!in_array($pluginName, $sorted, true)) {
191 $sorted[] = $pluginName;
192 }
193
194 return $sorted;
195 }
196 }
197