logbook/class/core/plugin/PluginManager.class.php
linarphy a8aa60ae83
Fix following first run
The code 'works' as is
2025-04-15 21:03:44 +02:00

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
}
}
?>