131 lines
3.9 KiB
PHP
131 lines
3.9 KiB
PHP
<?php
|
|
|
|
namespace core\plugin;
|
|
|
|
/**
|
|
* Manage link between plugins and core
|
|
*/
|
|
class PluginManager
|
|
{
|
|
/**
|
|
* Fetch a class that can be defined by pugins
|
|
*
|
|
* Plugin can "map" core class to their own class. For example,
|
|
* \core\log\clients\WonderfulClient can be defined by the plugin
|
|
* wonderful_plugin as the class
|
|
* \plugin\wonderful_plugin\log_clients\WonderfulClientV1, so that
|
|
* fetch_class('\\core\\log\\client\\WonderfulCLient') will return
|
|
* '\\plugin\\wonderful_plugin\\log_client\\WonderfulClientV1'.
|
|
*
|
|
* The plugin with the highest priority will override other values.
|
|
*
|
|
* Return the class name used by the plugin, not the object itself !
|
|
*
|
|
* @param \string $class_name Class name
|
|
*
|
|
* @return \string | null Return null if no class name was found
|
|
*/
|
|
public static function fetch_class(string $class_name) : string | null
|
|
{
|
|
if (!\core\is_class_name($class_name))
|
|
{
|
|
throw new \core\plugin\PluginException(\core\substitute(
|
|
_('{class name} is not a valid class name'),
|
|
array('class name' => $class_name),
|
|
));
|
|
}
|
|
foreach (self::fetch_plugins() as $plugin) # NOTE: first will override
|
|
{
|
|
$plugin_class_name = $plugin::fetch_class(class_name: $class_name);
|
|
if (!\is_null($temp_result))
|
|
{
|
|
return $plugin_class_name;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Fetch all plugins used in this system
|
|
*
|
|
* Plugins must define a class implementing \core\plugin\Plugin, which
|
|
* define the public properties and functionnalities of a plugin.
|
|
*
|
|
* The list of plugins returned is sorted by ascending priority, from
|
|
* high priority plugin to low one.
|
|
*
|
|
* A plugin with a priority of one will be used for an operation if no
|
|
* plugin with a higher priority (like 2) can do the operation.
|
|
*
|
|
* If no plugins are installed, the list will be empty.
|
|
*
|
|
* @return \SplPriorityQueue[\core\plugin\Plugin]
|
|
*/
|
|
public static function fetch_plugins() : \SplPriorityQueue
|
|
{
|
|
$plugins = \SplPriorityQueue();
|
|
$plugins_path = \core\Path(
|
|
'.' . \DIRECTORY_SEPARATOR . 'plugins',
|
|
);
|
|
if (!$plugins_path->exists())
|
|
{
|
|
return $plugins; # the folder does not exist, no plugins
|
|
}
|
|
foreach ($plugins_path->dirs() as $dir)
|
|
{
|
|
$plugin = self::fetch_plugin($dir);
|
|
if (!\is_int($plugin->configuration()->get('priority')))
|
|
{
|
|
throw new \core\plugin\PluginException(\core\substitute(
|
|
_('the plugin stored in {path} does not define its priority, as a priority must be an int, and a public attribute'),
|
|
array('path' => $dir->__toString()),
|
|
));
|
|
}
|
|
$plugins->insert($plugin, $plugin->configuration()->get('priority'));
|
|
}
|
|
return $plugins;
|
|
}
|
|
|
|
/**
|
|
* Fetch a plugin from a path
|
|
*
|
|
* A plugin must define a class implementing \core\plugin\Plugin, which
|
|
* define the public properties and functionnalities of a plugin.
|
|
*
|
|
* @param \core\Path $path Path to the plugin.
|
|
*
|
|
* @throws \FatalError The plugin do not define a class with the same
|
|
* name as its directory, or not in the namespace
|
|
* '\plugins'. Or the plugin have a forbidden name.
|
|
*
|
|
* @return \core\plugin\Plugin
|
|
*/
|
|
public static function fetch_plugin(
|
|
\core\Path $path,
|
|
) : \core\plugin\Plugin
|
|
{
|
|
if (!$path->append('Plugin.class.php')->exists())
|
|
{
|
|
throw new \core\plugin\PluginException(\core\substitute(
|
|
_('cannot fetch plugin {path} because there is no file named Plugin.class.php in it'),
|
|
array('path' => $path->__toString()),
|
|
));
|
|
}
|
|
|
|
$class_name = 'plugins\\' . $path->basename();
|
|
|
|
if (!\core\is_class_name($class_name))
|
|
{
|
|
throw new \core\plugin\PluginException(\core\substitute(
|
|
_('{name} is not a valid plugin name. A plugin name should be a valid PHP class name.'),
|
|
array('name' => $class_name),
|
|
));
|
|
}
|
|
|
|
\require_once($path->append('Plugin.class.php')->absPath()); # Manualy load the class
|
|
return new $class_name(); # WARN: Fail if the class_name is not exactly the same that the name of the plugin directory
|
|
}
|
|
}
|
|
|
|
?>
|