aboutsummaryrefslogtreecommitdiffhomepage
path: root/application/PluginManager.php
diff options
context:
space:
mode:
authorArthurHoaro <arthur@hoa.ro>2015-07-15 11:42:15 +0200
committerArthurHoaro <arthur@hoa.ro>2015-11-07 15:27:17 +0100
commit6fc14d530369740d27d6bd641369d4f5f5f04080 (patch)
tree2da553378e8f0ff367dcb677d6f519d1fb3e803c /application/PluginManager.php
parent38bedfbbcdd2a40e9f04f5753e0fd6f4fd513c21 (diff)
downloadShaarli-6fc14d530369740d27d6bd641369d4f5f5f04080.tar.gz
Shaarli-6fc14d530369740d27d6bd641369d4f5f5f04080.tar.zst
Shaarli-6fc14d530369740d27d6bd641369d4f5f5f04080.zip
Plugin system - CORE
see shaarli/Shaarli#275
Diffstat (limited to 'application/PluginManager.php')
-rw-r--r--application/PluginManager.php184
1 files changed, 184 insertions, 0 deletions
diff --git a/application/PluginManager.php b/application/PluginManager.php
new file mode 100644
index 00000000..e572ff7c
--- /dev/null
+++ b/application/PluginManager.php
@@ -0,0 +1,184 @@
1<?php
2
3/**
4 * Class PluginManager
5 *
6 * Use to manage, load and execute plugins.
7 *
8 * Using Singleton design pattern.
9 */
10class PluginManager
11{
12 /**
13 * PluginManager singleton instance.
14 * @var PluginManager $instance
15 */
16 private static $instance;
17
18 /**
19 * List of authorized plugins from configuration file.
20 * @var array $authorizedPlugins
21 */
22 private $authorizedPlugins;
23
24 /**
25 * List of loaded plugins.
26 * @var array $loadedPlugins
27 */
28 private $loadedPlugins = array();
29
30 /**
31 * Plugins subdirectory.
32 * @var string $PLUGINS_PATH
33 */
34 public static $PLUGINS_PATH = 'plugins';
35
36 /**
37 * Private constructor: new instances not allowed.
38 */
39 private function __construct()
40 {
41 }
42
43 /**
44 * Cloning isn't allowed either.
45 *
46 * @return void
47 */
48 private function __clone()
49 {
50 }
51
52 /**
53 * Return existing instance of PluginManager, or create it.
54 *
55 * @return PluginManager instance.
56 */
57 public static function getInstance()
58 {
59 if (!(self::$instance instanceof self)) {
60 self::$instance = new self();
61 }
62
63 return self::$instance;
64 }
65
66 /**
67 * Load plugins listed in $authorizedPlugins.
68 *
69 * @param array $authorizedPlugins Names of plugin authorized to be loaded.
70 *
71 * @return void
72 */
73 public function load($authorizedPlugins)
74 {
75 $this->authorizedPlugins = $authorizedPlugins;
76
77 $dirs = glob(self::$PLUGINS_PATH . '/*', GLOB_ONLYDIR);
78 $dirnames = array_map('basename', $dirs);
79 foreach ($this->authorizedPlugins as $plugin) {
80 $index = array_search($plugin, $dirnames);
81
82 // plugin authorized, but its folder isn't listed
83 if ($index === false) {
84 continue;
85 }
86
87 try {
88 $this->loadPlugin($dirs[$index], $plugin);
89 }
90 catch (PluginFileNotFoundException $e) {
91 error_log($e->getMessage());
92 }
93 }
94 }
95
96 /**
97 * Execute all plugins registered hook.
98 *
99 * @param string $hook name of the hook to trigger.
100 * @param array $data list of data to manipulate passed by reference.
101 * @param array $params additional parameters such as page target.
102 *
103 * @return void
104 */
105 public function executeHooks($hook, &$data, $params = array())
106 {
107 if (!empty($params['target'])) {
108 $data['_PAGE_'] = $params['target'];
109 }
110
111 if (isset($params['loggedin'])) {
112 $data['_LOGGEDIN_'] = $params['loggedin'];
113 }
114
115 foreach ($this->loadedPlugins as $plugin) {
116 $hookFunction = $this->buildHookName($hook, $plugin);
117
118 if (function_exists($hookFunction)) {
119 $data = call_user_func($hookFunction, $data);
120 }
121 }
122 }
123
124 /**
125 * Load a single plugin from its files.
126 * Add them in $loadedPlugins if successful.
127 *
128 * @param string $dir plugin's directory.
129 * @param string $pluginName plugin's name.
130 *
131 * @return void
132 * @throws PluginFileNotFoundException - plugin files not found.
133 */
134 private function loadPlugin($dir, $pluginName)
135 {
136 if (!is_dir($dir)) {
137 throw new PluginFileNotFoundException($pluginName);
138 }
139
140 $pluginFilePath = $dir . '/' . $pluginName . '.php';
141 if (!is_file($pluginFilePath)) {
142 throw new PluginFileNotFoundException($pluginName);
143 }
144
145 include_once $pluginFilePath;
146
147 $this->loadedPlugins[] = $pluginName;
148 }
149
150 /**
151 * Construct normalize hook name for a specific plugin.
152 *
153 * Format:
154 * hook_<plugin_name>_<hook_name>
155 *
156 * @param string $hook hook name.
157 * @param string $pluginName plugin name.
158 *
159 * @return string - plugin's hook name.
160 */
161 public function buildHookName($hook, $pluginName)
162 {
163 return 'hook_' . $pluginName . '_' . $hook;
164 }
165}
166
167/**
168 * Class PluginFileNotFoundException
169 *
170 * Raise when plugin files can't be found.
171 */
172class PluginFileNotFoundException extends Exception
173{
174 /**
175 * Construct exception with plugin name.
176 * Generate message.
177 *
178 * @param string $pluginName name of the plugin not found
179 */
180 public function __construct($pluginName)
181 {
182 $this->message = 'Plugin "'. $pluginName .'" files not found.';
183 }
184} \ No newline at end of file