]> git.immae.eu Git - github/shaarli/Shaarli.git/blame - application/plugin/PluginManager.php
Apply PHP Code Beautifier on source code for linter automatic fixes
[github/shaarli/Shaarli.git] / application / plugin / PluginManager.php
CommitLineData
6fc14d53 1<?php
53054b2b 2
e1850388
V
3namespace Shaarli\Plugin;
4
5use Shaarli\Config\ConfigManager;
6use Shaarli\Plugin\Exception\PluginFileNotFoundException;
6fc14d53
A
7
8/**
9 * Class PluginManager
10 *
11 * Use to manage, load and execute plugins.
6fc14d53
A
12 */
13class PluginManager
14{
6fc14d53
A
15 /**
16 * List of authorized plugins from configuration file.
e1850388 17 *
6fc14d53
A
18 * @var array $authorizedPlugins
19 */
1b8620b1 20 private $authorizedPlugins = [];
6fc14d53
A
21
22 /**
23 * List of loaded plugins.
e1850388 24 *
6fc14d53
A
25 * @var array $loadedPlugins
26 */
53054b2b 27 private $loadedPlugins = [];
6fc14d53 28
51def0d8
A
29 /**
30 * @var ConfigManager Configuration Manager instance.
31 */
32 protected $conf;
33
7fde6de1
A
34 /**
35 * @var array List of plugin errors.
36 */
37 protected $errors;
38
6fc14d53
A
39 /**
40 * Plugins subdirectory.
e1850388 41 *
6fc14d53
A
42 * @var string $PLUGINS_PATH
43 */
44 public static $PLUGINS_PATH = 'plugins';
45
dea0ba28
A
46 /**
47 * Plugins meta files extension.
e1850388 48 *
dea0ba28
A
49 * @var string $META_EXT
50 */
51 public static $META_EXT = 'meta';
52
6fc14d53 53 /**
51def0d8 54 * Constructor.
6fc14d53 55 *
51def0d8 56 * @param ConfigManager $conf Configuration Manager instance.
6fc14d53 57 */
51def0d8 58 public function __construct(&$conf)
6fc14d53 59 {
51def0d8 60 $this->conf = $conf;
53054b2b 61 $this->errors = [];
6fc14d53
A
62 }
63
64 /**
65 * Load plugins listed in $authorizedPlugins.
66 *
67 * @param array $authorizedPlugins Names of plugin authorized to be loaded.
68 *
69 * @return void
70 */
71 public function load($authorizedPlugins)
72 {
73 $this->authorizedPlugins = $authorizedPlugins;
74
75 $dirs = glob(self::$PLUGINS_PATH . '/*', GLOB_ONLYDIR);
76 $dirnames = array_map('basename', $dirs);
77 foreach ($this->authorizedPlugins as $plugin) {
78 $index = array_search($plugin, $dirnames);
79
80 // plugin authorized, but its folder isn't listed
81 if ($index === false) {
82 continue;
83 }
84
85 try {
86 $this->loadPlugin($dirs[$index], $plugin);
f211e417 87 } catch (PluginFileNotFoundException $e) {
6fc14d53
A
88 error_log($e->getMessage());
89 }
90 }
91 }
92
93 /**
94 * Execute all plugins registered hook.
95 *
e1850388
V
96 * @param string $hook name of the hook to trigger.
97 * @param array $data list of data to manipulate passed by reference.
98 * @param array $params additional parameters such as page target.
567967fd 99 *
6fc14d53
A
100 * @return void
101 */
53054b2b 102 public function executeHooks($hook, &$data, $params = [])
6fc14d53 103 {
4ff703e3
A
104 $metadataParameters = [
105 'target' => '_PAGE_',
106 'loggedin' => '_LOGGEDIN_',
107 'basePath' => '_BASE_PATH_',
3adbdc2a 108 'rootPath' => '_ROOT_PATH_',
4ff703e3
A
109 'bookmarkService' => '_BOOKMARK_SERVICE_',
110 ];
111
112 foreach ($metadataParameters as $parameter => $metaKey) {
113 if (array_key_exists($parameter, $params)) {
114 $data[$metaKey] = $params[$parameter];
115 }
80b708a8
A
116 }
117
6fc14d53
A
118 foreach ($this->loadedPlugins as $plugin) {
119 $hookFunction = $this->buildHookName($hook, $plugin);
120
121 if (function_exists($hookFunction)) {
7e3dc0ba
A
122 try {
123 $data = call_user_func($hookFunction, $data, $this->conf);
124 } catch (\Throwable $e) {
125 $error = $plugin . t(' [plugin incompatibility]: ') . $e->getMessage();
126 $this->errors = array_unique(array_merge($this->errors, [$error]));
127 }
6fc14d53
A
128 }
129 }
4ff703e3
A
130
131 foreach ($metadataParameters as $metaKey) {
132 unset($data[$metaKey]);
133 }
6fc14d53
A
134 }
135
136 /**
137 * Load a single plugin from its files.
7fde6de1 138 * Call the init function if it exists, and collect errors.
6fc14d53
A
139 * Add them in $loadedPlugins if successful.
140 *
141 * @param string $dir plugin's directory.
142 * @param string $pluginName plugin's name.
143 *
144 * @return void
e1850388 145 * @throws \Shaarli\Plugin\Exception\PluginFileNotFoundException - plugin files not found.
6fc14d53
A
146 */
147 private function loadPlugin($dir, $pluginName)
148 {
149 if (!is_dir($dir)) {
150 throw new PluginFileNotFoundException($pluginName);
151 }
152
153 $pluginFilePath = $dir . '/' . $pluginName . '.php';
154 if (!is_file($pluginFilePath)) {
155 throw new PluginFileNotFoundException($pluginName);
156 }
157
51def0d8 158 $conf = $this->conf;
6fc14d53
A
159 include_once $pluginFilePath;
160
7fde6de1
A
161 $initFunction = $pluginName . '_init';
162 if (function_exists($initFunction)) {
163 $errors = call_user_func($initFunction, $this->conf);
164 if (!empty($errors)) {
165 $this->errors = array_merge($this->errors, $errors);
166 }
167 }
168
6fc14d53
A
169 $this->loadedPlugins[] = $pluginName;
170 }
171
172 /**
173 * Construct normalize hook name for a specific plugin.
174 *
175 * Format:
176 * hook_<plugin_name>_<hook_name>
177 *
178 * @param string $hook hook name.
179 * @param string $pluginName plugin name.
180 *
181 * @return string - plugin's hook name.
182 */
183 public function buildHookName($hook, $pluginName)
184 {
185 return 'hook_' . $pluginName . '_' . $hook;
186 }
dea0ba28
A
187
188 /**
189 * Retrieve plugins metadata from *.meta (INI) files into an array.
190 * Metadata contains:
191 * - plugin description [description]
192 * - parameters split with ';' [parameters]
193 *
194 * Respects plugins order from settings.
195 *
196 * @return array plugins metadata.
197 */
198 public function getPluginsMeta()
199 {
53054b2b 200 $metaData = [];
dea0ba28
A
201 $dirs = glob(self::$PLUGINS_PATH . '/*', GLOB_ONLYDIR | GLOB_MARK);
202
203 // Browse all plugin directories.
204 foreach ($dirs as $pluginDir) {
205 $plugin = basename($pluginDir);
206 $metaFile = $pluginDir . $plugin . '.' . self::$META_EXT;
207 if (!is_file($metaFile) || !is_readable($metaFile)) {
208 continue;
209 }
210
211 $metaData[$plugin] = parse_ini_file($metaFile);
212 $metaData[$plugin]['order'] = array_search($plugin, $this->authorizedPlugins);
213
12266213
A
214 if (isset($metaData[$plugin]['description'])) {
215 $metaData[$plugin]['description'] = t($metaData[$plugin]['description']);
216 }
dea0ba28
A
217 // Read parameters and format them into an array.
218 if (isset($metaData[$plugin]['parameters'])) {
219 $params = explode(';', $metaData[$plugin]['parameters']);
220 } else {
53054b2b 221 $params = [];
dea0ba28 222 }
53054b2b 223 $metaData[$plugin]['parameters'] = [];
dea0ba28
A
224 foreach ($params as $param) {
225 if (empty($param)) {
226 continue;
227 }
228
15170b51
A
229 $metaData[$plugin]['parameters'][$param]['value'] = '';
230 // Optional parameter description in parameter.PARAM_NAME=
e1850388
V
231 if (isset($metaData[$plugin]['parameter.' . $param])) {
232 $metaData[$plugin]['parameters'][$param]['desc'] = t($metaData[$plugin]['parameter.' . $param]);
15170b51 233 }
dea0ba28
A
234 }
235 }
236
237 return $metaData;
238 }
7fde6de1
A
239
240 /**
241 * Return the list of encountered errors.
242 *
243 * @return array List of errors (empty array if none exists).
244 */
245 public function getErrors()
246 {
247 return $this->errors;
248 }
6fc14d53 249}