Skip to content
Extraits de code Groupes Projets
Manager.php 41,9 ko
Newer Older
  • Learn to ignore specific revisions
  •  * Piwik - free/libre analytics platform
    
    robocoder's avatar
    robocoder a validé
     *
    
    robocoder's avatar
    robocoder a validé
     * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
    
    robocoder's avatar
    robocoder a validé
     *
    
    namespace Piwik\Plugin;
    
    use Piwik\Application\Kernel\PluginList;
    
    use Piwik\Container\StaticContainer;
    
    mattab's avatar
    mattab a validé
    use Piwik\EventDispatcher;
    
    sgiehl's avatar
    sgiehl a validé
    use Piwik\Exception\PluginDeactivatedException;
    
    mattab's avatar
    mattab a validé
    use Piwik\Filesystem;
    
    mattab's avatar
    mattab a validé
    use Piwik\Log;
    
    mattab's avatar
    mattab a validé
    use Piwik\Plugin;
    
    use Piwik\Plugin\Dimension\ActionDimension;
    use Piwik\Plugin\Dimension\ConversionDimension;
    use Piwik\Plugin\Dimension\VisitDimension;
    use Piwik\Settings\Storage as SettingsStorage;
    
    mattab's avatar
    mattab a validé
    use Piwik\Updater;
    
    require_once PIWIK_INCLUDE_PATH . '/core/EventDispatcher.php';
    
     * The singleton that manages plugin loading/unloading and installation/uninstallation.
    
    class Manager
    
        /**
         * @return self
         */
        public static function getInstance()
        {
            return StaticContainer::get('Piwik\Plugin\Manager');
        }
    
    
        protected $pluginsToLoad = array();
    
        protected $doLoadPlugins = true;
    
        private $pluginsLoadedAndActivated;
    
    
        protected $loadedPlugins = array();
    
        const DEFAULT_THEME = "Morpheus";
    
    
        protected $doLoadAlwaysActivatedPlugins = true;
    
    
        // These are always activated and cannot be deactivated
    
        protected $pluginToAlwaysActivate = array(
            'CoreHome',
    
            'CoreConsole',
    
            'CoreVisualizations',
    
            'Installation',
            'SitesManager',
            'UsersManager',
    
            'WebsiteMeasurable',
    
    mattab's avatar
    mattab a validé
    
            // default Piwik theme, always enabled
    
    Thomas Steur's avatar
    Thomas Steur a validé
        private $trackerPluginsNotToLoad = array();
    
    
        /**
         * @var PluginList
         */
        private $pluginList;
    
        public function __construct(PluginList $pluginList)
        {
            $this->pluginList = $pluginList;
        }
    
    
        /**
         * Loads plugin that are enabled
         */
        public function loadActivatedPlugins()
        {
    
            $pluginsToLoad = $this->getActivatedPluginsFromConfig();
    
            $this->loadPlugins($pluginsToLoad);
        }
    
        /**
         * Called during Tracker
         */
        public function loadCorePluginsDuringTracker()
        {
    
            $pluginsToLoad = $this->pluginList->getActivatedPlugins();
    
    Thomas Steur's avatar
    Thomas Steur a validé
            $pluginsToLoad = array_diff($pluginsToLoad, $this->getTrackerPluginsNotToLoad());
    
        /**
         * @return array names of plugins that have been loaded
         */
        public function loadTrackerPlugins()
        {
    
            $cacheId = 'PluginsTracker';
            $cache = Cache::getEagerCache();
    
            if ($cache->contains($cacheId)) {
                $pluginsTracker = $cache->fetch($cacheId);
    
            } else {
                $this->unloadPlugins();
                $this->loadActivatedPlugins();
    
                $pluginsTracker = array();
    
                foreach ($this->loadedPlugins as $pluginName => $plugin) {
                    if ($this->isTrackerPlugin($plugin)) {
                        $pluginsTracker[] = $pluginName;
                    }
                }
    
                if (!empty($pluginsTracker)) {
    
                    $cache->save($cacheId, $pluginsTracker);
    
            if (empty($pluginsTracker)) {
    
    Thomas Steur's avatar
    Thomas Steur a validé
                $this->unloadPlugins();
    
    Thomas Steur's avatar
    Thomas Steur a validé
            $pluginsTracker = array_diff($pluginsTracker, $this->getTrackerPluginsNotToLoad());
    
            $this->doNotLoadAlwaysActivatedPlugins();
            $this->loadPlugins($pluginsTracker);
    
    Thomas Steur's avatar
    Thomas Steur a validé
    
            // we could simply unload all plugins first before loading plugins but this way it is much faster
            // since we won't have to create each plugin again and we won't have to parse each plugin metadata file
            // again etc
            $this->makeSureOnlyActivatedPluginsAreLoaded();
    
    
            return $pluginsTracker;
        }
    
    
    Thomas Steur's avatar
    Thomas Steur a validé
        /**
         * Do not load the specified plugins (used during testing, to disable Provider plugin)
         * @param array $plugins
         */
        public function setTrackerPluginsNotToLoad($plugins)
        {
            $this->trackerPluginsNotToLoad = $plugins;
        }
    
        /**
         * Get list of plugins to not load
         *
         * @return array
         */
        public function getTrackerPluginsNotToLoad()
        {
            return $this->trackerPluginsNotToLoad;
        }
    
    
    mattab's avatar
    mattab a validé
        // If a plugin hooks onto at least an event starting with "Tracker.", we load the plugin during tracker
        const TRACKER_EVENT_PREFIX = 'Tracker.';
    
    
        /**
         * @param $pluginName
         * @return bool
         */
        public function isPluginOfficialAndNotBundledWithCore($pluginName)
        {
            static $gitModules;
    
                $gitModules = file_get_contents(PIWIK_INCLUDE_PATH . '/.gitmodules');
            }
    
    mattab's avatar
    mattab a validé
            // All submodules are officially maintained plugins
    
    mattab's avatar
    mattab a validé
            $isSubmodule = false !== strpos($gitModules, "plugins/" . $pluginName . "\n");
    
    mattab's avatar
    mattab a validé
            return $isSubmodule;
    
        private function updatePluginsConfig($pluginsToLoad)
    
            $pluginsToLoad = $this->pluginList->sortPlugins($pluginsToLoad);
    
            $section = PiwikConfig::getInstance()->Plugins;
    
            $section['Plugins'] = $pluginsToLoad;
    
            PiwikConfig::getInstance()->Plugins = $section;
    
        }
    
        /**
         * Update PluginsInstalled config
         *
         * @param array $plugins Plugins
         */
        private function updatePluginsInstalledConfig($plugins)
        {
    
            $section = PiwikConfig::getInstance()->PluginsInstalled;
    
            $section['PluginsInstalled'] = $plugins;
    
            PiwikConfig::getInstance()->PluginsInstalled = $section;
    
        public function clearPluginsInstalledConfig()
        {
    
            $this->updatePluginsInstalledConfig(array());
    
        /**
         * Returns true if plugin is always activated
         *
    
         * @param string $name Name of plugin
    
        private function isPluginAlwaysActivated($name)
    
        {
            return in_array($name, $this->pluginToAlwaysActivate);
        }
    
    
        /**
         * Returns true if the plugin can be uninstalled. Any non-core plugin can be uninstalled.
         *
         * @param $name
         * @return bool
         */
    
        private function isPluginUninstallable($name)
    
            return !$this->isPluginBundledWithCore($name);
    
         * Returns `true` if a plugin has been activated.
    
         * @param string $name Name of plugin, eg, `'Actions'`.
    
         */
        public function isPluginActivated($name)
        {
            return in_array($name, $this->pluginsToLoad)
    
    Thomas Steur's avatar
    Thomas Steur a validé
            || ($this->doLoadAlwaysActivatedPlugins && $this->isPluginAlwaysActivated($name));
    
        /**
         * Checks whether the given plugin is activated, if not triggers an exception.
         *
         * @param  string $pluginName
         * @throws PluginDeactivatedException
         */
        public function checkIsPluginActivated($pluginName)
        {
            if (!$this->isPluginActivated($pluginName)) {
                throw new PluginDeactivatedException($pluginName);
            }
        }
    
    
         * Returns `true` if plugin is loaded (in memory).
    
         * @param string $name Name of plugin, eg, `'Acions'`.
    
         */
        public function isPluginLoaded($name)
        {
            return isset($this->loadedPlugins[$name]);
        }
    
        /**
         * Reads the directories inside the plugins/ directory and returns their names in an array
         *
         * @return array
         */
        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);
    
        public static function getPluginsDirectory()
    
    mattab's avatar
    mattab a validé
        {
            return PIWIK_INCLUDE_PATH . '/plugins/';
        }
    
    
        /**
         * Deactivate plugin
         *
         * @param string $pluginName Name of plugin
         */
        public function deactivatePlugin($pluginName)
        {
    
            // execute deactivate() to let the plugin do cleanups
            $this->executePluginDeactivate($pluginName);
    
            $this->unloadPluginFromMemory($pluginName);
    
            $this->removePluginFromConfig($pluginName);
    
    
            /**
             * Event triggered after a plugin has been deactivated.
             *
             * @param string $pluginName The plugin that has been deactivated.
             */
            Piwik::postEvent('PluginManager.pluginDeactivated', array($pluginName));
    
        /**
         * Tries to find the given components such as a Menu or Tasks implemented by plugins.
         * This method won't cache the found components. If you need to find the same component multiple times you might
         * want to cache the result to save a tiny bit of time.
         *
         * @param string $componentName     The name of the component you want to look for. In case you request a
         *                                  component named 'Menu' it'll look for a file named 'Menu.php' within the
         *                                  root of all plugin folders that implement a class named
         *                                  Piwik\Plugin\$PluginName\Menu.
         * @param string $expectedSubclass  If not empty, a check will be performed whether a found file extends the
         *                                  given subclass. If the requested file exists but does not extend this class
         *                                  a warning will be shown to advice a developer to extend this certain class.
         *
         * @return \stdClass[]
         */
        public function findComponents($componentName, $expectedSubclass)
        {
    
            $plugins    = $this->getPluginsLoadedAndActivated();
    
                $component = $plugin->findComponent($componentName, $expectedSubclass);
    
                if (!empty($component)) {
                    $components[] = $component;
                }
            }
    
            return $components;
        }
    
    
        public function findMultipleComponents($directoryWithinPlugin, $expectedSubclass)
        {
    
            $plugins = $this->getPluginsLoadedAndActivated();
    
            $found   = array();
    
            foreach ($plugins as $plugin) {
                $components = $plugin->findMultipleComponents($directoryWithinPlugin, $expectedSubclass);
    
                if (!empty($components)) {
                    $found = array_merge($found, $components);
                }
            }
    
            return $found;
        }
    
    
        /**
         * Uninstalls a Plugin (deletes plugin files from the disk)
         * Only deactivated plugins can be uninstalled
         *
         * @param $pluginName
    
         * @throws \Exception
         * @return bool
    
         */
        public function uninstallPlugin($pluginName)
        {
    
            if ($this->isPluginLoaded($pluginName)) {
    
                throw new \Exception("To uninstall the plugin $pluginName, first disable it in Piwik > Settings > Plugins");
    
            $this->loadAllPluginsAndGetTheirInfo();
    
            SettingsStorage\Backend\PluginSettingsTable::removeAllSettingsForPlugin($pluginName);
            SettingsStorage\Backend\MeasurableSettingsTable::removeAllSettingsForPlugin($pluginName);
    
            $this->executePluginDeactivate($pluginName);
            $this->executePluginUninstall($pluginName);
    
    
            $this->removePluginFromPluginsInstalledConfig($pluginName);
    
            $this->unloadPluginFromMemory($pluginName);
    
            $this->removePluginFromConfig($pluginName);
    
            $this->removeInstalledVersionFromOptionTable($pluginName);
    
    Julien Moumné's avatar
    Julien Moumné a validé
            $this->clearCache($pluginName);
    
            self::deletePluginFromFilesystem($pluginName);
    
            if ($this->isPluginInFilesystem($pluginName)) {
    
    
            /**
             * Event triggered after a plugin has been uninstalled.
             *
             * @param string $pluginName The plugin that has been uninstalled.
             */
            Piwik::postEvent('PluginManager.pluginUninstalled', array($pluginName));
    
    
    Julien Moumné's avatar
    Julien Moumné a validé
        /**
         * @param string $pluginName
         */
        private function clearCache($pluginName)
        {
    
            $this->resetTransientCache();
    
    Julien Moumné's avatar
    Julien Moumné a validé
            Filesystem::deleteAllCacheOnUpdate($pluginName);
        }
    
    
        public static function deletePluginFromFilesystem($plugin)
        {
    
            Filesystem::unlinkRecursive(PIWIK_INCLUDE_PATH . '/plugins/' . $plugin, $deleteRootToo = true);
    
         * @return array Error messages of plugin install fails
    
         */
        public function installLoadedPlugins()
        {
    
            Log::debug("Loaded plugins: " . implode(", ", array_keys($this->getLoadedPlugins())));
    
            foreach ($this->getLoadedPlugins() as $plugin) {
    
                $this->installPluginIfNecessary($plugin);
    
            }
        }
    
        /**
         * Activate the specified plugin and install (if needed)
         *
    
         * @param string $pluginName Name of plugin
    
         * @throws \Exception
    
         */
        public function activatePlugin($pluginName)
        {
    
            $plugins = $this->pluginList->getActivatedPlugins();
    
            if (in_array($pluginName, $plugins)) {
    
            if (!$this->isPluginInFilesystem($pluginName)) {
    
                throw new \Exception("Plugin '$pluginName' cannot be found in the filesystem in plugins/ directory.");
    
            $this->deactivateThemeIfTheme($pluginName);
    
    
            // Load plugin
    
            $plugin = $this->loadPlugin($pluginName);
            if ($plugin === null) {
    
                throw new \Exception("The plugin '$pluginName' was found in the filesystem, but could not be loaded.'");
    
            }
            $this->installPluginIfNecessary($plugin);
            $plugin->activate();
    
    
            EventDispatcher::getInstance()->postPendingEventsTo($plugin);
    
    
            $this->pluginsToLoad[] = $pluginName;
    
            $this->updatePluginsConfig($this->pluginsToLoad);
    
            PiwikConfig::getInstance()->forceSave();
    
    Julien Moumné's avatar
    Julien Moumné a validé
            $this->clearCache($pluginName);
    
    
            /**
             * Event triggered after a plugin has been activated.
             *
             * @param string $pluginName The plugin that has been activated.
             */
            Piwik::postEvent('PluginManager.pluginActivated', array($pluginName));
    
        public function isPluginInFilesystem($pluginName)
    
        {
            $existingPlugins = $this->readPluginsDirectory();
            $isPluginInFilesystem = array_search($pluginName, $existingPlugins) !== false;
    
            return $this->isValidPluginName($pluginName)
    
            && $isPluginInFilesystem;
    
    mattab's avatar
    mattab a validé
        /**
    
         * Returns the currently enabled theme.
    
         * If no theme is enabled, the **Morpheus** plugin is returned (this is the base and default theme).
    
    mattab's avatar
    mattab a validé
         *
    
    mattab's avatar
    mattab a validé
         */
    
    mattab's avatar
    mattab a validé
        {
            $plugins = $this->getLoadedPlugins();
    
            foreach ($plugins as $plugin) {
    
                if ($plugin->isTheme()
                    && $this->isPluginActivated($plugin->getPluginName())
                ) {
                    if ($plugin->getPluginName() != self::DEFAULT_THEME) {
    
                        return $plugin; // enabled theme (not default)
                    }
                    $theme = $plugin; // default theme
    
    mattab's avatar
    mattab a validé
                }
            }
    
    mattab's avatar
    mattab a validé
        }
    
    
    Julien Moumné's avatar
    Julien Moumné a validé
        /**
         * @param string $themeName
         * @throws \Exception
         * @return Theme
         */
        public function getTheme($themeName)
        {
            $plugins = $this->getLoadedPlugins();
    
    
    mattab's avatar
    mattab a validé
            foreach ($plugins as $plugin) {
                if ($plugin->isTheme() && $plugin->getPluginName() == $themeName) {
    
    Julien Moumné's avatar
    Julien Moumné a validé
                    return new Theme($plugin);
    
    Julien Moumné's avatar
    Julien Moumné a validé
            throw new \Exception('Theme not found : ' . $themeName);
        }
    
    
        public function getNumberOfActivatedPluginsExcludingAlwaysActivated()
    
        {
            $counter = 0;
    
            $pluginNames = $this->getLoadedPluginsName();
            foreach ($pluginNames as $pluginName) {
    
                if ($this->isPluginActivated($pluginName)
                    && !$this->isPluginAlwaysActivated($pluginName)) {
    
         * Returns info regarding all plugins. Loads plugins that can be loaded.
    
         * @return array An array that maps plugin names with arrays of plugin information. Plugin
         *               information consists of the following entries:
    
         *               - **activated**: Whether the plugin is activated.
         *               - **alwaysActivated**: Whether the plugin should always be activated,
         *                                      or not.
         *               - **uninstallable**: Whether the plugin is uninstallable or not.
         *               - **invalid**: If the plugin is invalid, this property will be set to true.
         *                              If the plugin is not invalid, this property will not exist.
         *               - **info**: If the plugin was loaded, will hold the plugin information.
    
         *                           See {@link Piwik\Plugin::getInformation()}.
    
        public function loadAllPluginsAndGetTheirInfo()
    
            $translator = StaticContainer::get('Piwik\Translation\Translator');
    
            $plugins = array();
    
            $listPlugins = array_merge(
                $this->readPluginsDirectory(),
    
                $this->pluginList->getActivatedPlugins()
    
            );
            $listPlugins = array_unique($listPlugins);
            foreach ($listPlugins as $pluginName) {
    
                // Hide plugins that are never going to be used
    
                if ($this->isPluginBogus($pluginName)) {
    
                // If the plugin is not core and looks bogus, do not load
    
                if ($this->isPluginThirdPartyAndBogus($pluginName)) {
    
                    $info = array(
                        'invalid'         => true,
                        'activated'       => false,
                        'alwaysActivated' => false,
                        'uninstallable'   => true,
                    );
                } else {
    
                    $translator->addDirectory(self::getPluginsDirectory() . $pluginName . '/lang');
    
                    $this->loadPlugin($pluginName);
                    $info = array(
                        'activated'       => $this->isPluginActivated($pluginName),
                        'alwaysActivated' => $this->isPluginAlwaysActivated($pluginName),
                        'uninstallable'   => $this->isPluginUninstallable($pluginName),
                    );
    
            }
    
            $loadedPlugins = $this->getLoadedPlugins();
            foreach ($loadedPlugins as $oPlugin) {
                $pluginName = $oPlugin->getPluginName();
    
    mattab's avatar
    mattab a validé
    
                $info = array(
                    'info' => $oPlugin->getInformation(),
                    'activated'       => $this->isPluginActivated($pluginName),
                    'alwaysActivated' => $this->isPluginAlwaysActivated($pluginName),
    
                    'missingRequirements' => $oPlugin->getMissingDependenciesAsString(),
    
    mattab's avatar
    mattab a validé
                    'uninstallable' => $this->isPluginUninstallable($pluginName),
                );
                $plugins[$pluginName] = $info;
    
            return $plugins;
        }
    
        protected static function isManifestFileFound($path)
        {
            return file_exists($path . "/" . MetadataLoader::PLUGIN_JSON_FILENAME);
        }
    
    
         * Returns `true` if the plugin is bundled with core or `false` if it is third party.
    
         * @param string $name The name of the plugin, eg, `'Actions'`.
         * @return bool
         */
    
        public function isPluginBundledWithCore($name)
    
            return $this->isPluginEnabledByDefault($name)
    
            || in_array($name, $this->pluginList->getCorePluginsDisabledByDefault())
    
            || $name == self::DEFAULT_THEME;
    
        /**
         * @param $pluginName
         * @return bool
         * @ignore
         */
        public function isPluginThirdPartyAndBogus($pluginName)
    
            if ($this->isPluginBundledWithCore($pluginName)) {
    
    mattab's avatar
    mattab a validé
                return false;
            }
    
            if ($this->isPluginBogus($pluginName)) {
    
    mattab's avatar
    mattab a validé
            }
    
    mattab's avatar
    mattab a validé
    
    
    mattab's avatar
    mattab a validé
            $path = $this->getPluginsDirectory() . $pluginName;
    
            if (!$this->isManifestFileFound($path)) {
    
    mattab's avatar
    mattab a validé
                return true;
            }
            return false;
    
         * Load AND activates the specified plugins. It will also overwrite all previously loaded plugins, so it acts
    
         * as a setter.
    
         * @param array $pluginsToLoad Array of plugins to load.
    
         */
        public function loadPlugins(array $pluginsToLoad)
        {
    
            $this->resetTransientCache();
    
            $this->pluginsToLoad = $this->makePluginsToLoad($pluginsToLoad);
    
            $this->reloadActivatedPlugins();
    
         * Disable plugin loading.
    
         */
        public function doNotLoadPlugins()
        {
            $this->doLoadPlugins = false;
        }
    
        /**
    
         * Disable loading of "always activated" plugins.
    
         */
        public function doNotLoadAlwaysActivatedPlugins()
        {
            $this->doLoadAlwaysActivatedPlugins = false;
        }
    
        /**
         * Execute postLoad() hook for loaded plugins
         */
        public function postLoadPlugins()
        {
            $plugins = $this->getLoadedPlugins();
            foreach ($plugins as $plugin) {
                $plugin->postLoad();
            }
        }
    
        /**
    
         * Returns an array containing the plugins class names (eg. 'UserCountry' and NOT 'UserCountry')
    
         *
         * @return array
         */
        public function getLoadedPluginsName()
        {
    
            return array_keys($this->getLoadedPlugins());
    
         * Returns an array mapping loaded plugin names with their plugin objects, eg,
    
         *     array(
         *         'UserCountry' => Plugin $pluginObject,
    
         *         'UserLanguage' => Plugin $pluginObject,
    
         */
        public function getLoadedPlugins()
        {
            return $this->loadedPlugins;
        }
    
    
        /**
         * @param  string $piwikVersion
         * @return Plugin[]
         */
        public function getIncompatiblePlugins($piwikVersion)
        {
            $plugins = $this->getLoadedPlugins();
    
            $incompatible = array();
            foreach ($plugins as $plugin) {
                if ($plugin->hasMissingDependencies($piwikVersion)) {
                    $incompatible[] = $plugin;
                }
            }
    
            return $incompatible;
        }
    
    
        /**
         * Returns an array of plugins that are currently loaded and activated,
         * mapping loaded plugin names with their plugin objects, eg,
         *
         *     array(
         *         'UserCountry' => Plugin $pluginObject,
    
         *         'UserLanguage' => Plugin $pluginObject,
    
         *     );
         *
         * @return Plugin[]
         */
        public function getPluginsLoadedAndActivated()
        {
    
            if (is_null($this->pluginsLoadedAndActivated)) {
                $enabled = $this->getActivatedPlugins();
    
    mattab's avatar
    mattab a validé
    
    
                if (empty($enabled)) {
                    return array();
                }
    
                $plugins = $this->getLoadedPlugins();
                $enabled = array_combine($enabled, $enabled);
                $plugins = array_intersect_key($plugins, $enabled);
    
                $this->pluginsLoadedAndActivated = $plugins;
    
    mattab's avatar
    mattab a validé
            }
    
    
            return $this->pluginsLoadedAndActivated;
    
        /**
         * Returns a list of all names of currently activated plugin eg,
         *
         *     array(
         *         'UserCountry'
    
         *         'UserLanguage'
    
         *     );
         *
         * @return string[]
         */
        public function getActivatedPlugins()
        {
            return $this->pluginsToLoad;
        }
    
    
        public function getActivatedPluginsFromConfig()
        {
    
            $plugins = $this->pluginList->getActivatedPlugins();
    
         * @param string $name The name of the plugin, eg, `'Actions'`.
         * @throws \Exception If the plugin has not been loaded.
    
         */
        public function getLoadedPlugin($name)
        {
    
            if (!isset($this->loadedPlugins[$name]) || is_null($this->loadedPlugins[$name])) {
    
                throw new \Exception("The plugin '$name' has not been loaded.");
    
            }
            return $this->loadedPlugins[$name];
        }
    
        /**
         * Load the plugins classes installed.
         * Register the observers for every plugin.
         */
    
        private function reloadActivatedPlugins()
    
            $pluginsToPostPendingEventsTo = array();
    
            foreach ($this->pluginsToLoad as $pluginName) {
    
                $pluginsToPostPendingEventsTo = $this->reloadActivatedPlugin($pluginName, $pluginsToPostPendingEventsTo);
            }
    
            // post pending events after all plugins are successfully loaded
            foreach ($pluginsToPostPendingEventsTo as $plugin) {
                EventDispatcher::getInstance()->postPendingEventsTo($plugin);
            }
        }
    
        private function reloadActivatedPlugin($pluginName, $pluginsToPostPendingEventsTo)
        {
            if ($this->isPluginLoaded($pluginName) || $this->isPluginThirdPartyAndBogus($pluginName)) {
                return $pluginsToPostPendingEventsTo;
            }
    
            $newPlugin = $this->loadPlugin($pluginName);
    
            if ($newPlugin === null) {
                return $pluginsToPostPendingEventsTo;
            }
    
            $requirements = $newPlugin->getMissingDependencies();
    
            if (!empty($requirements)) {
                foreach ($requirements as $requirement) {
                    $possiblePluginName = $requirement['requirement'];
                    if (in_array($possiblePluginName, $this->pluginsToLoad, $strict = true)) {
                        $pluginsToPostPendingEventsTo = $this->reloadActivatedPlugin($possiblePluginName, $pluginsToPostPendingEventsTo);
                    }
    
            if ($newPlugin->hasMissingDependencies()) {
    
    
                // at this state we do not know yet whether current user has super user access. We do not even know
                // if someone is actually logged in.
    
                $message  = Piwik::translate('CorePluginsAdmin_WeCouldNotLoadThePluginAsItHasMissingDependencies', array($pluginName, $newPlugin->getMissingDependenciesAsString()));
    
                $message .= ' ';
                $message .= Piwik::translate('General_PleaseContactYourPiwikAdministrator');
    
                $notification = new Notification($message);
                $notification->context = Notification::CONTEXT_ERROR;
    
                Notification\Manager::notify('PluginManager_PluginUnloaded', $notification);
    
                return $pluginsToPostPendingEventsTo;
    
    
            $pluginsToPostPendingEventsTo[] = $newPlugin;
    
            return $pluginsToPostPendingEventsTo;
    
        public function getIgnoredBogusPlugins()
        {
            $ignored = array();
    
            foreach ($this->pluginsToLoad as $pluginName) {
                if ($this->isPluginThirdPartyAndBogus($pluginName)) {
    
        /**
         * Returns the name of all plugins found in this Piwik instance
    
    mattab's avatar
    mattab a validé
         * (including those not enabled and themes)
    
         *
         * @return array
         */
        public static function getAllPluginsNames()
        {
    
            $pluginList = StaticContainer::get('Piwik\Application\Kernel\PluginList');
    
    
            $pluginsToLoad = array_merge(
                self::getInstance()->readPluginsDirectory(),
    
                $pluginList->getCorePluginsDisabledByDefault()
    
            );
            $pluginsToLoad = array_values(array_unique($pluginsToLoad));
            return $pluginsToLoad;
        }
    
    
         * Loads the plugin filename and instantiates the plugin with the given name, eg. UserCountry.
         * Contrary to loadPlugins() it does not activate the plugin, it only loads it.
    
         * @throws \Exception
         * @return Plugin|null
    
         */
        public function loadPlugin($pluginName)
        {
            if (isset($this->loadedPlugins[$pluginName])) {
                return $this->loadedPlugins[$pluginName];
            }
    
    mattab's avatar
    mattab a validé
            $newPlugin = $this->makePluginClass($pluginName);
    
            $this->addLoadedPlugin($pluginName, $newPlugin);
            return $newPlugin;
        }
    
    
        public function isValidPluginName($pluginName)
        {
    
            return (bool) preg_match('/^[a-zA-Z]([a-zA-Z0-9_]*)$/D', $pluginName);
    
    mattab's avatar
    mattab a validé
        /**
         * @param $pluginName
    
         * @return Plugin
         * @throws \Exception
    
    mattab's avatar
    mattab a validé
         */
        protected function makePluginClass($pluginName)
        {
    
            $pluginFileName = sprintf("%s/%s.php", $pluginName, $pluginName);
    
            if (!$this->isValidPluginName($pluginName)) {
                throw new \Exception(sprintf("The plugin filename '%s' is not a valid plugin name", $pluginFileName));
    
            $path = self::getPluginsDirectory() . $pluginFileName;
    
    mattab's avatar
    mattab a validé
                // Create the smallest minimal Piwik Plugin
    
                // Eg. Used for Morpheus default theme which does not have a Morpheus.php file
    
    mattab's avatar
    mattab a validé
            require_once $path;
    
            $namespacedClass = $this->getClassNamePlugin($pluginName);
    
            if (!class_exists($namespacedClass, false)) {
    
                throw new \Exception("The class $pluginClassName couldn't be found in the file '$path'");
    
            if (!($newPlugin instanceof Plugin)) {
                throw new \Exception("The plugin $pluginClassName in the file $path must inherit from Plugin.");
    
        protected function getClassNamePlugin($pluginName)
        {
            $className = $pluginName;
    
            if ($pluginName == 'API') {
    
                $className = 'Plugin';
            }
            return "\\Piwik\\Plugins\\$pluginName\\$className";
        }
    
    
        private function resetTransientCache()
        {
            $this->pluginsLoadedAndActivated = null;
        }
    
    
         * @param Plugin|string $plugin
         * @throws \Exception
    
         */
        public function unloadPlugin($plugin)
        {