2 namespace Shaarli\Plugin
;
4 use Shaarli\Config\ConfigManager
;
5 use Shaarli\Plugin\Exception\PluginFileNotFoundException
;
10 * Use to manage, load and execute plugins.
15 * List of authorized plugins from configuration file.
17 * @var array $authorizedPlugins
19 private $authorizedPlugins = [];
22 * List of loaded plugins.
24 * @var array $loadedPlugins
26 private $loadedPlugins = array();
29 * @var ConfigManager Configuration Manager instance.
34 * @var array List of plugin errors.
39 * Plugins subdirectory.
41 * @var string $PLUGINS_PATH
43 public static $PLUGINS_PATH = 'plugins';
46 * Plugins meta files extension.
48 * @var string $META_EXT
50 public static $META_EXT = 'meta';
55 * @param ConfigManager $conf Configuration Manager instance.
57 public function __construct(&$conf)
60 $this->errors
= array();
64 * Load plugins listed in $authorizedPlugins.
66 * @param array $authorizedPlugins Names of plugin authorized to be loaded.
70 public function load($authorizedPlugins)
72 $this->authorizedPlugins
= $authorizedPlugins;
74 $dirs = glob(self
::$PLUGINS_PATH . '/*', GLOB_ONLYDIR
);
75 $dirnames = array_map('basename', $dirs);
76 foreach ($this->authorizedPlugins
as $plugin) {
77 $index = array_search($plugin, $dirnames);
79 // plugin authorized, but its folder isn't listed
80 if ($index === false) {
85 $this->loadPlugin($dirs[$index], $plugin);
86 } catch (PluginFileNotFoundException
$e) {
87 error_log($e->getMessage());
93 * Execute all plugins registered hook.
95 * @param string $hook name of the hook to trigger.
96 * @param array $data list of data to manipulate passed by reference.
97 * @param array $params additional parameters such as page target.
101 public function executeHooks($hook, &$data, $params = array())
103 if (!empty($params['target'])) {
104 $data['_PAGE_'] = $params['target'];
107 if (isset($params['loggedin'])) {
108 $data['_LOGGEDIN_'] = $params['loggedin'];
111 if (isset($params['basePath'])) {
112 $data['_BASE_PATH_'] = $params['basePath'];
115 foreach ($this->loadedPlugins
as $plugin) {
116 $hookFunction = $this->buildHookName($hook, $plugin);
118 if (function_exists($hookFunction)) {
120 $data = call_user_func($hookFunction, $data, $this->conf
);
121 } catch (\Throwable
$e) {
122 $error = $plugin . t(' [plugin incompatibility]: ') . $e->getMessage();
123 $this->errors
= array_unique(array_merge($this->errors
, [$error]));
130 * Load a single plugin from its files.
131 * Call the init function if it exists, and collect errors.
132 * Add them in $loadedPlugins if successful.
134 * @param string $dir plugin's directory.
135 * @param string $pluginName plugin's name.
138 * @throws \Shaarli\Plugin\Exception\PluginFileNotFoundException - plugin files not found.
140 private function loadPlugin($dir, $pluginName)
143 throw new PluginFileNotFoundException($pluginName);
146 $pluginFilePath = $dir . '/' . $pluginName . '.php';
147 if (!is_file($pluginFilePath)) {
148 throw new PluginFileNotFoundException($pluginName);
152 include_once $pluginFilePath;
154 $initFunction = $pluginName . '_init';
155 if (function_exists($initFunction)) {
156 $errors = call_user_func($initFunction, $this->conf
);
157 if (!empty($errors)) {
158 $this->errors
= array_merge($this->errors
, $errors);
162 $this->loadedPlugins
[] = $pluginName;
166 * Construct normalize hook name for a specific plugin.
169 * hook_<plugin_name>_<hook_name>
171 * @param string $hook hook name.
172 * @param string $pluginName plugin name.
174 * @return string - plugin's hook name.
176 public function buildHookName($hook, $pluginName)
178 return 'hook_' . $pluginName . '_' . $hook;
182 * Retrieve plugins metadata from *.meta (INI) files into an array.
184 * - plugin description [description]
185 * - parameters split with ';' [parameters]
187 * Respects plugins order from settings.
189 * @return array plugins metadata.
191 public function getPluginsMeta()
194 $dirs = glob(self
::$PLUGINS_PATH . '/*', GLOB_ONLYDIR
| GLOB_MARK
);
196 // Browse all plugin directories.
197 foreach ($dirs as $pluginDir) {
198 $plugin = basename($pluginDir);
199 $metaFile = $pluginDir . $plugin . '.' . self
::$META_EXT;
200 if (!is_file($metaFile) || !is_readable($metaFile)) {
204 $metaData[$plugin] = parse_ini_file($metaFile);
205 $metaData[$plugin]['order'] = array_search($plugin, $this->authorizedPlugins
);
207 if (isset($metaData[$plugin]['description'])) {
208 $metaData[$plugin]['description'] = t($metaData[$plugin]['description']);
210 // Read parameters and format them into an array.
211 if (isset($metaData[$plugin]['parameters'])) {
212 $params = explode(';', $metaData[$plugin]['parameters']);
216 $metaData[$plugin]['parameters'] = array();
217 foreach ($params as $param) {
222 $metaData[$plugin]['parameters'][$param]['value'] = '';
223 // Optional parameter description in parameter.PARAM_NAME=
224 if (isset($metaData[$plugin]['parameter.' . $param])) {
225 $metaData[$plugin]['parameters'][$param]['desc'] = t($metaData[$plugin]['parameter.' . $param]);
234 * Return the list of encountered errors.
236 * @return array List of errors (empty array if none exists).
238 public function getErrors()
240 return $this->errors
;