Plugin system: allow plugins to provide custom routes
- each route will be prefixed by `/plugin/<plugin_name>` - add a new template for plugins rendering - add a live example in the demo_plugin Check out the "Plugin System" documentation for more detail. Related to #143
This commit is contained in:
parent
6f9e0609f4
commit
a6e9c08499
13 changed files with 270 additions and 13 deletions
application/plugin
|
@ -4,6 +4,7 @@ namespace Shaarli\Plugin;
|
|||
|
||||
use Shaarli\Config\ConfigManager;
|
||||
use Shaarli\Plugin\Exception\PluginFileNotFoundException;
|
||||
use Shaarli\Plugin\Exception\PluginInvalidRouteException;
|
||||
|
||||
/**
|
||||
* Class PluginManager
|
||||
|
@ -26,6 +27,14 @@ class PluginManager
|
|||
*/
|
||||
private $loadedPlugins = [];
|
||||
|
||||
/** @var array List of registered routes. Contains keys:
|
||||
* - `method`: HTTP method, GET/POST/PUT/PATCH/DELETE
|
||||
* - `route` (path): without prefix, e.g. `/up/{variable}`
|
||||
* It will be later prefixed by `/plugin/<plugin name>/`.
|
||||
* - `callable` string, function name or FQN class's method, e.g. `demo_plugin_custom_controller`.
|
||||
*/
|
||||
protected $registeredRoutes = [];
|
||||
|
||||
/**
|
||||
* @var ConfigManager Configuration Manager instance.
|
||||
*/
|
||||
|
@ -86,6 +95,9 @@ class PluginManager
|
|||
$this->loadPlugin($dirs[$index], $plugin);
|
||||
} catch (PluginFileNotFoundException $e) {
|
||||
error_log($e->getMessage());
|
||||
} catch (\Throwable $e) {
|
||||
$error = $plugin . t(' [plugin incompatibility]: ') . $e->getMessage();
|
||||
$this->errors = array_unique(array_merge($this->errors, [$error]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -166,6 +178,22 @@ class PluginManager
|
|||
}
|
||||
}
|
||||
|
||||
$registerRouteFunction = $pluginName . '_register_routes';
|
||||
$routes = null;
|
||||
if (function_exists($registerRouteFunction)) {
|
||||
$routes = call_user_func($registerRouteFunction);
|
||||
}
|
||||
|
||||
if ($routes !== null) {
|
||||
foreach ($routes as $route) {
|
||||
if (static::validateRouteRegistration($route)) {
|
||||
$this->registeredRoutes[$pluginName][] = $route;
|
||||
} else {
|
||||
throw new PluginInvalidRouteException($pluginName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->loadedPlugins[] = $pluginName;
|
||||
}
|
||||
|
||||
|
@ -237,6 +265,14 @@ class PluginManager
|
|||
return $metaData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array List of registered custom routes by plugins.
|
||||
*/
|
||||
public function getRegisteredRoutes(): array
|
||||
{
|
||||
return $this->registeredRoutes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of encountered errors.
|
||||
*
|
||||
|
@ -246,4 +282,32 @@ class PluginManager
|
|||
{
|
||||
return $this->errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether provided input is valid to register a new route.
|
||||
* It must contain keys `method`, `route`, `callable` (all strings).
|
||||
*
|
||||
* @param string[] $input
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected static function validateRouteRegistration(array $input): bool
|
||||
{
|
||||
if (
|
||||
!array_key_exists('method', $input)
|
||||
|| !in_array(strtoupper($input['method']), ['GET', 'PUT', 'PATCH', 'POST', 'DELETE'])
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!array_key_exists('route', $input) || !preg_match('#^[a-z\d/\.\-_]+$#', $input['route'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!array_key_exists('callable', $input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
26
application/plugin/exception/PluginInvalidRouteException.php
Normal file
26
application/plugin/exception/PluginInvalidRouteException.php
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shaarli\Plugin\Exception;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Class PluginFileNotFoundException
|
||||
*
|
||||
* Raise when plugin files can't be found.
|
||||
*/
|
||||
class PluginInvalidRouteException extends Exception
|
||||
{
|
||||
/**
|
||||
* Construct exception with plugin name.
|
||||
* Generate message.
|
||||
*
|
||||
* @param string $pluginName name of the plugin not found
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->message = 'trying to register invalid route.';
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue