X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=application%2Fplugin%2FPluginManager.php;h=7fc0cb047db70d1ca33d8f72529b57ff598b579e;hb=a6e9c08499f9f79dad88cb3ae9eacda0e0c34c96;hp=2d93cb3a2173c58bada5803b8ca4fd522819991f;hpb=7e3dc0ba98bf019c2804e5c74fb6061b16fb712f;p=github%2Fshaarli%2FShaarli.git diff --git a/application/plugin/PluginManager.php b/application/plugin/PluginManager.php index 2d93cb3a..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,18 +111,20 @@ class PluginManager * * @return void */ - public function executeHooks($hook, &$data, $params = array()) + public function executeHooks($hook, &$data, $params = []) { - if (!empty($params['target'])) { - $data['_PAGE_'] = $params['target']; - } + $metadataParameters = [ + 'target' => '_PAGE_', + 'loggedin' => '_LOGGEDIN_', + 'basePath' => '_BASE_PATH_', + 'rootPath' => '_ROOT_PATH_', + 'bookmarkService' => '_BOOKMARK_SERVICE_', + ]; - if (isset($params['loggedin'])) { - $data['_LOGGEDIN_'] = $params['loggedin']; - } - - if (isset($params['basePath'])) { - $data['_BASE_PATH_'] = $params['basePath']; + foreach ($metadataParameters as $parameter => $metaKey) { + if (array_key_exists($parameter, $params)) { + $data[$metaKey] = $params[$parameter]; + } } foreach ($this->loadedPlugins as $plugin) { @@ -124,6 +139,10 @@ class PluginManager } } } + + foreach ($metadataParameters as $metaKey) { + unset($data[$metaKey]); + } } /** @@ -159,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; } @@ -190,7 +225,7 @@ class PluginManager */ public function getPluginsMeta() { - $metaData = array(); + $metaData = []; $dirs = glob(self::$PLUGINS_PATH . '/*', GLOB_ONLYDIR | GLOB_MARK); // Browse all plugin directories. @@ -211,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; @@ -230,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. * @@ -239,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; + } }