Skip to content
Extraits de code Groupes Projets
Manager.php 42,3 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\Config as PiwikConfig;
    
    mattab's avatar
    mattab a validé
    use Piwik\EventDispatcher;
    use Piwik\Filesystem;
    
    mattab's avatar
    mattab a validé
    use Piwik\Log;
    
    mattab's avatar
    mattab a validé
    use Piwik\Option;
    
    mattab's avatar
    mattab a validé
    use Piwik\Plugin;
    
    use Piwik\Tracker;
    
    use Piwik\Translate;
    
    mattab's avatar
    mattab a validé
    use Piwik\Updater;
    
    use Piwik\SettingsServer;
    
    use Piwik\Plugin\Dimension\ActionDimension;
    use Piwik\Plugin\Dimension\ConversionDimension;
    use Piwik\Plugin\Dimension\VisitDimension;
    
    require_once PIWIK_INCLUDE_PATH . '/core/EventDispatcher.php';
    
     * The singleton that manages plugin loading/unloading and installation/uninstallation.
    
    robocoder's avatar
    robocoder a validé
     *
    
     * @method static Manager getInstance()
    
        protected $pluginsToLoad = array();
    
        protected $doLoadPlugins = true;
    
        protected $loadedPlugins = array();
    
        const DEFAULT_THEME = "Morpheus";
    
    
        protected $doLoadAlwaysActivatedPlugins = true;
    
    
        // These are always activated and cannot be deactivated
    
        protected $pluginToAlwaysActivate = array(
            'CoreHome',
            'CoreUpdater',
            'CoreAdminHome',
    
            'CoreConsole',
    
            'CoreVisualizations',
    
            'Installation',
            'SitesManager',
            'UsersManager',
            'API',
            'Proxy',
            'LanguagesManager',
    
    mattab's avatar
    mattab a validé
    
            // default Piwik theme, always enabled
    
        // Plugins bundled with core package, disabled by default
    
        protected $corePluginsDisabledByDefault = array(
            'DBStats',
    
            'ExampleCommand',
            'ExampleSettingsPlugin',
            'ExampleUI',
            'ExampleVisualization',
    
            'ExampleTracker',
    
    mattab's avatar
    mattab a validé
        );
    
    
        // Themes bundled with core package, disabled by default
    
    mattab's avatar
    mattab a validé
        protected $coreThemesDisabledByDefault = array(
    
            'ExampleTheme'
    
    Thomas Steur's avatar
    Thomas Steur a validé
        private $trackerPluginsNotToLoad = array();
    
    
        /**
         * Loads plugin that are enabled
         */
        public function loadActivatedPlugins()
        {
            $pluginsToLoad = Config::getInstance()->Plugins['Plugins'];
            $this->loadPlugins($pluginsToLoad);
        }
    
        /**
         * Called during Tracker
         */
        public function loadCorePluginsDuringTracker()
        {
            $pluginsToLoad = Config::getInstance()->Plugins['Plugins'];
    
    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()
        {
    
            $cache = new PersistentCache('PluginsTracker');
    
            if ($cache->has()) {
                $pluginsTracker = $cache->get();
            } else {
    
                $this->unloadPlugins();
                $this->loadActivatedPlugins();
    
                $pluginsTracker = array();
    
                foreach ($this->loadedPlugins as $pluginName => $plugin) {
                    if ($this->isTrackerPlugin($plugin)) {
                        $pluginsTracker[] = $pluginName;
                    }
                }
    
                if (!empty($pluginsTracker)) {
                    $cache->set($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é
        public function getCorePluginsDisabledByDefault()
        {
    
    mattab's avatar
    mattab a validé
            return array_merge( $this->corePluginsDisabledByDefault, $this->coreThemesDisabledByDefault);
    
    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->sortPluginsSameOrderAsGlobalConfig($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() );
    
            PiwikConfig::getInstance()->forceSave();
            PiwikConfig::getInstance()->init();
    
        /**
         * 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));
    
         * 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);
    
            $this->clearCache($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();
    
            \Piwik\Settings\Manager::cleanupPluginSettings($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)) {
    
    Julien Moumné's avatar
    Julien Moumné a validé
        /**
         * @param string $pluginName
         */
        private function clearCache($pluginName)
        {
            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()
        {
    
    mattab's avatar
    mattab a validé
            Log::verbose("Loaded plugins: " . implode(", ", array_keys($this->getLoadedPlugins())));
    
    mattab's avatar
    mattab a validé
            $messages = array();
    
            foreach ($this->getLoadedPlugins() as $plugin) {
                try {
                    $this->installPluginIfNecessary($plugin);
    
                } catch (\Exception $e) {
    
                    $messages[] = $e->getMessage();
    
        }
    
        /**
         * Activate the specified plugin and install (if needed)
         *
    
         * @param string $pluginName Name of plugin
    
         * @throws \Exception
    
         */
        public function activatePlugin($pluginName)
        {
    
            $plugins = PiwikConfig::getInstance()->Plugins['Plugins'];
    
            if (in_array($pluginName, $plugins)) {
    
                throw new \Exception("Plugin '$pluginName' already activated.");
    
            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));
    
        protected function isPluginInFilesystem($pluginName)
        {
            $existingPlugins = $this->readPluginsDirectory();
            $isPluginInFilesystem = array_search($pluginName, $existingPlugins) !== false;
    
            return Filesystem::isValidFilename($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 getNumberOfActivatedPlugins()
        {
            $counter = 0;
    
            $pluginNames = $this->getLoadedPluginsName();
            foreach ($pluginNames as $pluginName) {
                if ($this->isPluginActivated($pluginName)) {
                    $counter++;
                }
            }
    
            return $counter;
        }
    
    
         * 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()
    
            $language = Translate::getLanguageToLoad();
    
    
            $plugins = array();
    
            $listPlugins = array_merge(
                $this->readPluginsDirectory(),
    
                PiwikConfig::getInstance()->Plugins['Plugins']
    
            );
            $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 {
    
                    $this->loadTranslation($pluginName, $language);
    
                    $this->loadPlugin($pluginName);
                    $info = array(
                        'activated'       => $this->isPluginActivated($pluginName),
                        'alwaysActivated' => $this->isPluginAlwaysActivated($pluginName),
                        'uninstallable'   => $this->isPluginUninstallable($pluginName),
                    );
    
            }
            $this->loadPluginTranslations();
    
            $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->getMissingDependencies(),
                    '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)
    
    mattab's avatar
    mattab a validé
                    || in_array($name, $this->getCorePluginsDisabledByDefault())
                    || $name == self::DEFAULT_THEME;
    
        }
    
        protected 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->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;
        }
    
        /**
         * Load translations for loaded plugins
         *
    
         * @param bool|string $language Optional language code
    
         */
        public function loadPluginTranslations($language = false)
        {
            if (empty($language)) {
    
                $language = Translate::getLanguageToLoad();
    
            $cache    = new CacheFile('tracker', 43200); // ttl=12hours
            $cacheKey = 'PluginTranslations';
    
            if (!empty($language)) {
                $cacheKey .= '-' . trim($language);
    
    
            if (!empty($this->loadedPlugins)) {
                // makes sure to create a translation in case loaded plugins change (ie Tests vs Tracker vs UI etc)
                $cacheKey .= '-' . md5(implode('', $this->getLoadedPluginsName()));
            }
    
    
            $translations = $cache->get($cacheKey);
    
            if (!empty($translations) &&
    
                !Development::isEnabled()) {
    
                Translate::mergeTranslationArray($translations);
                return;
            }
    
            $translations = array();
            $pluginNames  = self::getAllPluginsNames();
    
            foreach ($pluginNames as $pluginName) {
    
                if ($this->isPluginLoaded($pluginName) ||
                    $this->isPluginBundledWithCore($pluginName)) {
    
                    $this->loadTranslation($pluginName, $language);
    
                    if (isset($GLOBALS['Piwik_translations'][$pluginName])) {
                        $translations[$pluginName] = $GLOBALS['Piwik_translations'][$pluginName];
                    }
    
        }
    
        /**
         * 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,
         *         'UserSettings' => 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,
         *         'UserSettings' => Plugin $pluginObject,
         *     );
         *
         * @return Plugin[]
         */
        public function getPluginsLoadedAndActivated()
        {
    
            $plugins = $this->getLoadedPlugins();
            $enabled = $this->getActivatedPlugins();
    
    mattab's avatar
    mattab a validé
    
    
    mattab's avatar
    mattab a validé
                return array();
            }
    
            $enabled = array_combine($enabled, $enabled);
            $plugins = array_intersect_key($plugins, $enabled);
            return $plugins;
        }
    
    
        /**
         * Returns a list of all names of currently activated plugin eg,
         *
         *     array(
         *         'UserCountry'
         *         'UserSettings'
         *     );
         *
         * @return string[]
         */
        public function getActivatedPlugins()
        {
            return $this->pluginsToLoad;
        }
    
    
         * @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])) {
    
                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) {
    
                if (!$this->isPluginLoaded($pluginName)
    
                    && !$this->isPluginThirdPartyAndBogus($pluginName)
                ) {
    
                    $newPlugin = $this->loadPlugin($pluginName);
                    if ($newPlugin === null) {
                        continue;
                    }
    
                    if ($newPlugin->hasMissingDependencies()) {
                        $this->deactivatePlugin($pluginName);
                        continue;
                    }
    
    
                    $pluginsToPostPendingEventsTo[] = $newPlugin;
    
    
            // post pending events after all plugins are successfully loaded
            foreach ($pluginsToPostPendingEventsTo as $plugin) {
                EventDispatcher::getInstance()->postPendingEventsTo($plugin);
            }
    
        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()
        {
            $pluginsToLoad = array_merge(
                PiwikConfig::getInstance()->Plugins['Plugins'],
                self::getInstance()->readPluginsDirectory(),
                self::getInstance()->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;
        }
    
        /**
         * @param $pluginName
    
         * @return Plugin
         * @throws \Exception
    
    mattab's avatar
    mattab a validé
         */
        protected function makePluginClass($pluginName)
        {
    
            $pluginFileName = sprintf("%s/%s.php", $pluginName, $pluginName);
    
            if (!Filesystem::isValidFilename($pluginName)) {
    
                throw new \Exception(sprintf("The plugin filename '%s' is not a valid filename", $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";
        }
    
    
         * @param Plugin|string $plugin
         * @throws \Exception
    
         */
        public function unloadPlugin($plugin)
        {
    
            if (!($plugin instanceof Plugin)) {
    
                $oPlugin = $this->loadPlugin($plugin);
                if ($oPlugin === null) {
                    unset($this->loadedPlugins[$plugin]);
                    return;
                }
    
                $plugin = $oPlugin;
            }
    
            unset($this->loadedPlugins[$plugin->getPluginName()]);
        }
    
        /**
         * Unload all loaded plugins
         */
        public function unloadPlugins()
        {
            $pluginsLoaded = $this->getLoadedPlugins();
            foreach ($pluginsLoaded as $plugin) {
                $this->unloadPlugin($plugin);
            }