Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Steur <tsteur@users.noreply.github.com>2019-03-15 01:24:36 +0300
committerdiosmosis <diosmosis@users.noreply.github.com>2019-03-15 01:24:36 +0300
commit6395855aa7f3813cc7f413a18d31505ea26ba32a (patch)
tree2a3157954dd3c29cc024bf7093df53b63be94dd6 /core/Plugin/Manager.php
parentd7c932710e690d87ea62c3ec94ae65fa5bd05b05 (diff)
Support multiple plugin paths (#14051)
* do not hard code plugins directory * remove method that is not needed for now * use plugins directory in more places * some work on supporting multiple plugin directories * use more unique name * couple fixes * and another fix * sort plugins * adjust languagesmanager * adjust more usages * Update Manager.php * adding a plugin to test * more tests * make sure plugin resources can be located in custom directory * adding more tests * rewrite image paths * handle more cases * add tests * make sure to load plugin * trying to fix test * trying it this way * load plugin * fix ui test? * testing if tests succeed this way * another test * load custom dir plugin * load plugin in ui fixture * change the update statement * remove update script * delete column * fix ui test * make it work for tests * fix some tests * Fix merge.
Diffstat (limited to 'core/Plugin/Manager.php')
-rw-r--r--core/Plugin/Manager.php180
1 files changed, 165 insertions, 15 deletions
diff --git a/core/Plugin/Manager.php b/core/Plugin/Manager.php
index d25234c735..f48f8416fb 100644
--- a/core/Plugin/Manager.php
+++ b/core/Plugin/Manager.php
@@ -12,11 +12,13 @@ namespace Piwik\Plugin;
use Piwik\Application\Kernel\PluginList;
use Piwik\Cache;
use Piwik\Columns\Dimension;
+use Piwik\Common;
use Piwik\Config;
use Piwik\Config as PiwikConfig;
use Piwik\Container\StaticContainer;
use Piwik\Development;
use Piwik\EventDispatcher;
+use Piwik\Exception\Exception;
use Piwik\Exception\PluginDeactivatedException;
use Piwik\Filesystem;
use Piwik\Log;
@@ -26,7 +28,6 @@ use Piwik\Plugin;
use Piwik\Plugin\Dimension\ActionDimension;
use Piwik\Plugin\Dimension\ConversionDimension;
use Piwik\Plugin\Dimension\VisitDimension;
-use Piwik\Plugins\Marketplace\Api\Client;
use Piwik\Settings\Storage as SettingsStorage;
use Piwik\SettingsPiwik;
use Piwik\Theme;
@@ -52,6 +53,8 @@ class Manager
protected $doLoadPlugins = true;
+ protected static $pluginsToPathCache = array();
+
private $pluginsLoadedAndActivated;
/**
@@ -316,21 +319,164 @@ class Manager
*/
public function readPluginsDirectory()
{
- $pluginsName = _glob(self::getPluginsDirectory() . '*', GLOB_ONLYDIR);
$result = array();
- if ($pluginsName != false) {
- foreach ($pluginsName as $path) {
- if (self::pluginStructureLooksValid($path)) {
- $result[] = basename($path);
+ foreach (self::getPluginsDirectories() as $pluginsDir) {
+ $pluginsName = _glob($pluginsDir . '*', GLOB_ONLYDIR);
+ if ($pluginsName != false) {
+ foreach ($pluginsName as $path) {
+ if (self::pluginStructureLooksValid($path)) {
+ $result[] = basename($path);
+ }
}
}
}
+
+ sort($result);
+
return $result;
}
+ public static function initPluginDirectories()
+ {
+ $envDirs = getenv('MATOMO_PLUGIN_DIRS');
+ if (!empty($envDirs)) {
+ // we expect it in the format `absoluteStorageDir1;webrootPathRelative1:absoluteStorageDir2;webrootPathRelative1`
+ if (empty($GLOBALS['MATOMO_PLUGIN_DIRS'])) {
+ $GLOBALS['MATOMO_PLUGIN_DIRS'] = array();
+ }
+
+ $envDirs = explode(':', $envDirs);
+ foreach ($envDirs as $envDir) {
+ $envDir = explode(';', $envDir);
+ $absoluteDir = rtrim($envDir[0], '/') . '/';
+ $GLOBALS['MATOMO_PLUGIN_DIRS'][] = array(
+ 'pluginsPathAbsolute' => $absoluteDir,
+ 'webrootDirRelativeToMatomo' => isset($envDir[1]) ? $envDir[1] : null,
+ );
+ }
+ }
+
+ if (!empty($GLOBALS['MATOMO_PLUGIN_DIRS'])) {
+ foreach ($GLOBALS['MATOMO_PLUGIN_DIRS'] as $pluginDir => &$settings) {
+ if (!isset($settings['pluginsPathAbsolute'])) {
+ throw new \Exception('Missing "pluginsPathAbsolute" configuration for plugin dir');
+ }
+ if (!isset($settings['webrootDirRelativeToMatomo'])) {
+ throw new \Exception('Missing "webrootDirRelativeToMatomo" configuration for plugin dir');
+ }
+ }
+
+ $pluginDirs = self::getPluginsDirectories();
+ if (count($pluginDirs) > 1) {
+ spl_autoload_register(function ($className) use ($pluginDirs) {
+ if (strpos($className, 'Piwik\Plugins\\') === 0) {
+ $withoutPrefix = str_replace('Piwik\Plugins\\', '', $className);
+ $path = str_replace('\\', DIRECTORY_SEPARATOR, $withoutPrefix) . '.php';
+ foreach ($pluginDirs as $pluginsDirectory) {
+ if (file_exists($pluginsDirectory . $path)) {
+ require_once $pluginsDirectory . $path;
+ }
+ }
+ }
+ });
+ }
+ }
+ }
+
+ public static function getAlternativeWebRootDirectories()
+ {
+ $dirs = array();
+
+ if (!empty($GLOBALS['MATOMO_PLUGIN_DIRS'])) {
+ foreach ($GLOBALS['MATOMO_PLUGIN_DIRS'] as $pluginDir) {
+ $absolute = rtrim($pluginDir['pluginsPathAbsolute'], '/') . '/';
+ $relative = rtrim($pluginDir['webrootDirRelativeToMatomo'], '/') . '/';
+ $dirs[$absolute] = $relative;
+ }
+ }
+
+ return $dirs;
+ }
+
+ /**
+ * Returns the path to all plugins directories. Each plugins directory may contain several plugins.
+ * All paths have a trailing slash '/'.
+ * @return string[]
+ * @api
+ */
+ public static function getPluginsDirectories()
+ {
+ $dirs = array(self::getPluginsDirectory());
+
+ if (!empty($GLOBALS['MATOMO_PLUGIN_DIRS'])) {
+ $extraDirs = array_map(function ($dir) {
+ return rtrim($dir['pluginsPathAbsolute'], '/') . '/';
+ }, $GLOBALS['MATOMO_PLUGIN_DIRS']);
+ $dirs = array_merge($dirs, $extraDirs);
+ }
+
+ return $dirs;
+ }
+
+ private static function getPluginRealPath($path)
+ {
+ if (strpos($path, '../') !== false) {
+ // for tests, only do it when needed re performance etc
+ $real = realpath($path);
+ if ($real && Common::stringEndsWith($path, '/')) {
+ return rtrim($real, '/') . '/';
+ }
+ if ($real) {
+ return $real;
+ }
+ }
+ return $path;
+ }
+
+ /**
+ * Gets the path to a specific plugin. If the plugin does not exist in any plugins folder, the default plugins
+ * folder will be assumed.
+ *
+ * @param $pluginName
+ * @return mixed|string
+ * @api
+ */
+ public static function getPluginDirectory($pluginName)
+ {
+ if (isset(self::$pluginsToPathCache[$pluginName])) {
+ return self::$pluginsToPathCache[$pluginName];
+ }
+
+ $corePluginsDir = PIWIK_INCLUDE_PATH . 'plugins/' . $pluginName;
+ if (is_dir($corePluginsDir)) {
+ // for faster performance
+ self::$pluginsToPathCache[$pluginName] = self::getPluginRealPath($corePluginsDir);
+ return self::$pluginsToPathCache[$pluginName];
+ }
+
+ foreach (self::getPluginsDirectories() as $dir) {
+ $path = $dir . $pluginName;
+ if (is_dir($path)) {
+ self::$pluginsToPathCache[$pluginName] = self::getPluginRealPath($path);
+ return $path;
+ }
+ }
+
+ // assume default directory when plugin does not exist just yet
+ return self::getPluginsDirectory() . $pluginName;
+ }
+
+ /**
+ * Returns the path to the directory where core plugins are located. Please note since Matomo 3.9
+ * plugins may also be located in other directories and therefore this method has been deprecated.
+ * @deprecated since Matomo 3.9.0 use {@link (getPluginsDirectories())} or {@link getPluginDirectory($pluginName)} instead
+ * @return string
+ */
public static function getPluginsDirectory()
{
- return PIWIK_INCLUDE_PATH . '/plugins/';
+ $path = rtrim(PIWIK_INCLUDE_PATH, '/') . '/plugins/';
+ $path = self::getPluginRealPath($path);
+ return $path;
}
/**
@@ -459,8 +605,11 @@ class Manager
public static function deletePluginFromFilesystem($plugin)
{
- $pluginDir = self::getPluginsDirectory();
- Filesystem::unlinkRecursive($pluginDir . $plugin, $deleteRootToo = true);
+ $pluginDir = self::getPluginDirectory($plugin);
+ if (strpos($pluginDir, PIWIK_INCLUDE_PATH) === 0) {
+ // only delete files for plugins within matomo directory...
+ Filesystem::unlinkRecursive($pluginDir, $deleteRootToo = true);
+ }
}
/**
@@ -633,7 +782,7 @@ class Manager
'uninstallable' => true,
);
} else {
- $translator->addDirectory(self::getPluginsDirectory() . $pluginName . '/lang');
+ $translator->addDirectory(self::getPluginDirectory($pluginName) . '/lang');
$this->loadPlugin($pluginName);
$info = array(
'activated' => $this->isPluginActivated($pluginName),
@@ -694,7 +843,8 @@ class Manager
return true;
}
- $path = self::getPluginsDirectory() . $pluginName;
+ $path = self::getPluginDirectory($pluginName);
+
if (!$this->isManifestFileFound($path)) {
return true;
}
@@ -1006,14 +1156,14 @@ class Manager
*/
protected function makePluginClass($pluginName)
{
- $pluginFileName = sprintf("%s/%s.php", $pluginName, $pluginName);
$pluginClassName = $pluginName;
if (!$this->isValidPluginName($pluginName)) {
- throw new \Exception(sprintf("The plugin filename '%s' is not a valid plugin name", $pluginFileName));
+ throw new \Exception(sprintf("The plugin name '%s' is not a valid plugin name", $pluginName));
}
- $path = self::getPluginsDirectory() . $pluginFileName;
+ $path = self::getPluginDirectory($pluginName);
+ $path = sprintf('%s/%s.php', $path, $pluginName);
if (!file_exists($path)) {
// Create the smallest minimal Piwik Plugin
@@ -1470,7 +1620,7 @@ class Manager
/** @var Translator $translator */
$translator = StaticContainer::get('Piwik\Translation\Translator');
foreach ($this->getAllPluginsNames() as $pluginName) {
- $translator->addDirectory(self::getPluginsDirectory() . $pluginName . '/lang');
+ $translator->addDirectory(self::getPluginDirectory($pluginName) . '/lang');
}
}
}