Minor cleanups to the PluginManager.

Cleans up docblocks and makes most helper methods more permissive of incorrectly cased plugin identifiers. Replaces #4838 & #4837. Credit to @mjuavin for the case insensitivity fixes.
This commit is contained in:
Luke Towers 2020-04-01 21:30:54 -06:00
parent e4571c3dd4
commit 61b4ef6a47
1 changed files with 111 additions and 70 deletions

View File

@ -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
*/