X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=application%2Fplugin%2FPluginManager.php;h=7fc0cb047db70d1ca33d8f72529b57ff598b579e;hb=a6e9c08499f9f79dad88cb3ae9eacda0e0c34c96;hp=1b2197c9d8d0aa1af56d44842ed18c3fa4f619de;hpb=543b16b4f4bbde4e9857490e2175e44b4d941eb3;p=github%2Fshaarli%2FShaarli.git diff --git a/application/plugin/PluginManager.php b/application/plugin/PluginManager.php index 1b2197c9..7fc0cb04 100644 --- a/application/plugin/PluginManager.php +++ b/application/plugin/PluginManager.php @@ -1,8 +1,10 @@ /`. + * - `callable` string, function name or FQN class's method, e.g. `demo_plugin_custom_controller`. + */ + protected $registeredRoutes = []; /** * @var ConfigManager Configuration Manager instance. @@ -57,7 +67,7 @@ class PluginManager public function __construct(&$conf) { $this->conf = $conf; - $this->errors = array(); + $this->errors = []; } /** @@ -85,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])); } } } @@ -98,12 +111,13 @@ class PluginManager * * @return void */ - public function executeHooks($hook, &$data, $params = array()) + public function executeHooks($hook, &$data, $params = []) { $metadataParameters = [ 'target' => '_PAGE_', 'loggedin' => '_LOGGEDIN_', 'basePath' => '_BASE_PATH_', + 'rootPath' => '_ROOT_PATH_', 'bookmarkService' => '_BOOKMARK_SERVICE_', ]; @@ -164,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; } @@ -195,7 +225,7 @@ class PluginManager */ public function getPluginsMeta() { - $metaData = array(); + $metaData = []; $dirs = glob(self::$PLUGINS_PATH . '/*', GLOB_ONLYDIR | GLOB_MARK); // Browse all plugin directories. @@ -216,9 +246,9 @@ class PluginManager if (isset($metaData[$plugin]['parameters'])) { $params = explode(';', $metaData[$plugin]['parameters']); } else { - $params = array(); + $params = []; } - $metaData[$plugin]['parameters'] = array(); + $metaData[$plugin]['parameters'] = []; foreach ($params as $param) { if (empty($param)) { continue; @@ -235,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. * @@ -244,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; + } }