diff --git a/modules/system/classes/PluginManager.php b/modules/system/classes/PluginManager.php index 4d8894c92..26e38c10d 100644 --- a/modules/system/classes/PluginManager.php +++ b/modules/system/classes/PluginManager.php @@ -3,15 +3,15 @@ use Db; use App; use Str; +use Log; use File; use Lang; -use Log; use View; use Config; use Schema; +use SystemException; use RecursiveIteratorIterator; use RecursiveDirectoryIterator; -use SystemException; /** * Plugin manager @@ -29,7 +29,7 @@ class PluginManager protected $app; /** - * Container object used for storing plugin information objects. + * @var array Container array used for storing plugin information objects. */ protected $plugins; @@ -44,22 +44,22 @@ class PluginManager protected $normalizedMap = []; /** - * @var bool Check if all plugins have had the register() method called. + * @var bool Flag to indicate that all plugins have had the register() method called by registerAll() being called on this class. */ protected $registered = false; /** - * @var bool Check if all plugins have had the boot() method called. + * @var bool Flag to indicate that all plugins have had the boot() method called by bootAll() being called on this class. */ protected $booted = false; /** - * @var string Path to the disarm file. + * @var string Path to the JSON encoded file containing the disabled plugins. */ protected $metaFile; /** - * @var array Collection of disabled plugins + * @var array Array of disabled plugins */ protected $disabledPlugins = []; @@ -69,7 +69,7 @@ class PluginManager protected $registrationMethodCache = []; /** - * @var boolean Prevent all plugins from registering or booting + * @var bool Prevent all plugins from registering or booting */ public static $noInit = false; @@ -99,7 +99,8 @@ class PluginManager } /** - * Finds all available plugins and loads them in to the $plugins array. + * Finds all available plugins and loads them in to the $this->plugins array. + * * @return array */ public function loadPlugins() @@ -119,15 +120,16 @@ class PluginManager } /** - * Loads a single plugin in to the manager. + * Loads a single plugin into the manager. + * * @param string $namespace Eg: Acme\Blog * @param string $path Eg: plugins_path().'/acme/blog'; * @return void */ public function loadPlugin($namespace, $path) { - $className = $namespace.'\Plugin'; - $classPath = $path.'/Plugin.php'; + $className = $namespace . '\Plugin'; + $classPath = $path . '/Plugin.php'; try { // Autoloader failed? @@ -169,6 +171,8 @@ class PluginManager /** * Runs the register() method on all plugins. Can only be called once. + * + * @param bool $force Defaults to false, if true will force the re-registration of all plugins. Use unregisterAll() instead. * @return void */ public function registerAll($force = false) @@ -185,7 +189,8 @@ class PluginManager } /** - * Unregisters all plugins: the negative of registerAll(). + * Unregisters all plugins: the inverse of registerAll(). + * * @return void */ public function unregisterAll() @@ -196,8 +201,9 @@ class PluginManager /** * Registers a single plugin object. - * @param PluginBase $plugin - * @param string $pluginId + * + * @param PluginBase $plugin The instantiated Plugin object + * @param string $pluginId The string identifier for the plugin * @return void */ public function registerPlugin($plugin, $pluginId = null) @@ -210,6 +216,13 @@ class PluginManager return; } + /** + * Verify that the provided plugin should be registered + */ + if ($plugin->disabled || (self::$noInit && !$plugin->elevated)) { + return; + } + $pluginPath = $this->getPluginPath($plugin); $pluginNamespace = strtolower($pluginId); @@ -221,10 +234,6 @@ class PluginManager Lang::addNamespace($pluginNamespace, $langPath); } - if ($plugin->disabled) { - return; - } - /* * Register plugin class autoloaders */ @@ -233,9 +242,10 @@ class PluginManager ComposerManager::instance()->autoload($pluginPath . '/vendor'); } - if (!self::$noInit || $plugin->elevated) { - $plugin->register(); - } + /** + * Run the plugin's register() method + */ + $plugin->register(); /* * Register configuration path @@ -257,7 +267,7 @@ class PluginManager * Add init, if available */ $initFile = $pluginPath . '/init.php'; - if (!self::$noInit && File::exists($initFile)) { + if (File::exists($initFile)) { require $initFile; } @@ -272,6 +282,9 @@ class PluginManager /** * Runs the boot() method on all plugins. Can only be called once. + * + * @param bool $force Defaults to false, if true will force the re-booting of all plugins + * @return void */ public function bootAll($force = false) { @@ -287,23 +300,25 @@ class PluginManager } /** - * Registers a single plugin object. + * Boots the provided plugin object. + * * @param PluginBase $plugin * @return void */ public function bootPlugin($plugin) { - if (!$plugin || $plugin->disabled) { + if (!$plugin || $plugin->disabled || (self::$noInit && !$plugin->elevated)) { return; } - if (!self::$noInit || $plugin->elevated) { - $plugin->boot(); - } + $plugin->boot(); } /** * Returns the directory path to a plugin + * + * @param PluginBase|string $id The plugin to get the path for + * @return string|null */ public function getPluginPath($id) { @@ -317,8 +332,9 @@ class PluginManager /** * Check if a plugin exists and is enabled. - * @param string $id Plugin identifier, eg: Namespace.PluginName - * @return boolean + * + * @param string $id Plugin identifier, eg: Namespace.PluginName + * @return bool */ public function exists($id) { @@ -326,8 +342,10 @@ class PluginManager } /** - * Returns an array with all registered plugins + * Returns an array with all enabled plugins * The index is the plugin namespace, the value is the plugin information object. + * + * @return array */ public function getPlugins() { @@ -336,41 +354,42 @@ class PluginManager /** * Returns a plugin registration class based on its namespace (Author\Plugin). + * + * @param string $namespace + * @return PluginBase|null */ public function findByNamespace($namespace) { - if (!$this->hasPlugin($namespace)) { - return null; - } + $identifier = $this->getIdentifier($namespace); - $classId = $this->getIdentifier($namespace); - - return $this->plugins[$classId]; + return $this->plugins[$identifier] ?? null; } /** * Returns a plugin registration class based on its identifier (Author.Plugin). + * + * @param string|PluginBase $identifier + * @return PluginBase|null */ public function findByIdentifier($identifier) { if (!isset($this->plugins[$identifier])) { - $identifier = $this->normalizeIdentifier($identifier); + $code = $this->getIdentifier($identifier); + $identifier = $this->normalizeIdentifier($code); } - if (!isset($this->plugins[$identifier])) { - return null; - } - - return $this->plugins[$identifier]; + return $this->plugins[$identifier] ?? null; } /** * Checks to see if a plugin has been registered. + * + * @param string|PluginBase + * @return bool */ public function hasPlugin($namespace) { $classId = $this->getIdentifier($namespace); - $normalized = $this->normalizeIdentifier($classId); return isset($this->plugins[$normalized]); @@ -378,6 +397,8 @@ class PluginManager /** * Returns a flat array of vendor plugin namespaces and their paths + * + * @return array ['Author\Plugin' => 'plugins/author/plugin'] */ public function getPluginNamespaces() { @@ -396,6 +417,8 @@ class PluginManager /** * Returns a 2 dimensional array of vendors and their plugins. + * + * @return array ['vendor' => ['author' => 'plugins/author/plugin']] */ public function getVendorAndPluginNames() { @@ -427,9 +450,10 @@ class PluginManager } /** - * Resolves a plugin identifier from a plugin class name or object. + * Resolves a plugin identifier (Author.Plugin) from a plugin class name or object. + * * @param mixed Plugin class name or object - * @return string Identifier in format of Vendor.Plugin + * @return string Identifier in format of Author.Plugin */ public function getIdentifier($namespace) { @@ -463,7 +487,8 @@ class PluginManager } /** - * Spins over every plugin object and collects the results of a method call. + * Spins over every plugin object and collects the results of a method call. Results are cached in memory. + * * @param string $methodName * @return array */ @@ -491,6 +516,11 @@ class PluginManager // Disability // + /** + * Clears the disabled plugins cache file + * + * @return void + */ public function clearDisabledCache() { File::delete($this->metaFile); @@ -498,7 +528,9 @@ class PluginManager } /** - * Loads all disables plugins from the meta file. + * Loads all disabled plugins from the cached JSON file. + * + * @return void */ protected function loadDisabled() { @@ -513,8 +545,7 @@ class PluginManager if (File::exists($path)) { $disabled = json_decode(File::get($path), true) ?: []; $this->disabledPlugins = array_merge($this->disabledPlugins, $disabled); - } - else { + } else { $this->populateDisabledPluginsFromDb(); $this->writeDisabled(); } @@ -523,21 +554,22 @@ class PluginManager /** * Determines if a plugin is disabled by looking at the meta information * or the application configuration. - * @return boolean + * + * @param string|PluginBase $id + * @return bool */ public function isDisabled($id) { $code = $this->getIdentifier($id); + $normalized = $this->normalizeIdentifier($code); - if (array_key_exists($code, $this->disabledPlugins)) { - return true; - } - - return false; + return isset($this->disabledPlugins[$normalized]); } /** * Write the disabled plugins to a meta file. + * + * @return void */ protected function writeDisabled() { @@ -546,6 +578,7 @@ class PluginManager /** * Populates information about disabled plugins from database + * * @return void */ protected function populateDisabledPluginsFromDb() @@ -567,13 +600,15 @@ class PluginManager /** * Disables a single plugin in the system. - * @param string $id Plugin code/namespace - * @param bool $isUser Set to true if disabled by the user - * @return bool + * + * @param string|PluginBase $id Plugin code/namespace + * @param bool $isUser Set to true if disabled by the user, false by default + * @return bool Returns false if the plugin was already disabled, true otherwise */ public function disablePlugin($id, $isUser = false) { $code = $this->getIdentifier($id); + $code = $this->normalizeIdentifier($code); if (array_key_exists($code, $this->disabledPlugins)) { return false; } @@ -590,13 +625,15 @@ class PluginManager /** * Enables a single plugin in the system. - * @param string $id Plugin code/namespace - * @param bool $isUser Set to true if enabled by the user - * @return bool + * + * @param string|PluginBase $id Plugin code/namespace + * @param bool $isUser Set to true if enabled by the user, false by default + * @return bool Returns false if the plugin wasn't already disabled or if the user disabled a plugin that the system is trying to re-enable, true otherwise */ public function enablePlugin($id, $isUser = false) { $code = $this->getIdentifier($id); + $code = $this->normalizeIdentifier($code); if (!array_key_exists($code, $this->disabledPlugins)) { return false; } @@ -654,6 +691,7 @@ class PluginManager /** * Cross checks all plugins and their dependancies, if not met plugins * are disabled and vice versa. + * * @return void */ protected function loadDependencies() @@ -668,16 +706,14 @@ class PluginManager foreach ($required as $require) { if (!$pluginObj = $this->findByIdentifier($require)) { $disable = true; - } - elseif ($pluginObj->disabled) { + } elseif ($pluginObj->disabled) { $disable = true; } } if ($disable) { $this->disablePlugin($id); - } - else { + } else { $this->enablePlugin($id); } } @@ -686,7 +722,9 @@ class PluginManager /** * Sorts a collection of plugins, in the order that they should be actioned, * according to their given dependencies. Least dependent come first. - * @return array Collection of sorted plugin identifiers + * + * @return array Array of sorted plugin identifiers and instantiated classes ['Author.Plugin' => PluginBase] + * @throws SystemException If a possible circular dependency is detected */ protected function sortDependencies() { @@ -708,7 +746,7 @@ class PluginManager /* * Get dependencies and remove any aliens */ - $depends = $this->getDependencies($plugin) ?: []; + $depends = $this->getDependencies($plugin); $depends = array_filter($depends, function ($pluginCode) { return isset($this->plugins[$pluginCode]); }); @@ -752,17 +790,18 @@ class PluginManager /** * Returns the plugin identifiers that are required by the supplied plugin. + * * @param string $plugin Plugin identifier, object or class * @return array */ public function getDependencies($plugin) { if (is_string($plugin) && (!$plugin = $this->findByIdentifier($plugin))) { - return false; + return []; } if (!isset($plugin->require) || !$plugin->require) { - return null; + return []; } return is_array($plugin->require) ? $plugin->require : [$plugin->require]; @@ -785,6 +824,7 @@ class PluginManager /** * Completely roll back and delete a plugin from the system. + * * @param string $id Plugin code/namespace * @return void */ @@ -805,6 +845,7 @@ class PluginManager /** * Tears down a plugin's database tables and rebuilds them. + * * @param string $id Plugin code/namespace * @return void */