more work on the plugins system
[diogenes.git] / include / Plugins.php
1 <?php
2 /*
3 * Copyright (C) 2003-2004 Polytechnique.org
4 * http://opensource.polytechnique.org/
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 // dependency on PEAR
22 require_once 'System.php';
23 require_once 'Tree/Node.php';
24 require_once 'Plugin/Skel.php';
25
26
27 /** This class describes Diogenes' plugins.
28 */
29 class Diogenes_Plugins
30 {
31 /** Directory that holds the plugins cache files */
32 var $cachedir;
33
34 /** Directory that holds the plugins */
35 var $plugdir;
36
37 /** Plugins that will be sent to trace */
38 var $log = array();
39
40 /** Constructs a new holder for Diogenes plugins.
41 *
42 * @param $dbh
43 * @param $plugdir
44 * @param $cachedir
45 */
46 function Diogenes_Plugins(&$dbh, $plugdir, $cachedir)
47 {
48 $this->dbh =& $dbh;
49 $this->plugdir = $plugdir;
50 $this->cachedir = $cachedir;
51 }
52
53
54 /** Return the path of the cache file
55 *
56 * @param $barrel
57 */
58 function cacheFile($barrel)
59 {
60 $cachefile = $this->cachedir . "/" . ($barrel ? $barrel : "__diogenes__") . ".plugins";
61 return $cachefile;
62 }
63
64
65 /** Return the cache entry for specified plugin
66 *
67 * @param $cache
68 * @param $barrel
69 * @param $page
70 * @param $plugin
71 */
72 function cacheGet($cache, $barrel, $page, $plugin)
73 {
74 $p_node = $this->cacheGetPageNode($cache, $barrel, $page);
75 return $p_node->data[$plugin];
76 }
77
78
79 /** Return the cache entry for specified plugin
80 *
81 * @param $cache
82 * @param $barrel
83 * @param $page
84 * @param $plugin
85 */
86 function cacheGetPageNode($cache, $barrel, $page)
87 {
88 if ($page) {
89 $p_node = $cache->getChild($page);
90 } else {
91 $p_node = $cache;
92 }
93 return $p_node;
94 }
95
96
97 /** List the plugins that are active in a given context
98 *
99 * @param $cache
100 * @param $barrel
101 * @param $page
102 */
103 function cacheGetActive($cache, $barrel, $page)
104 {
105 $p_node = $this->cacheGetPageNode($cache, $barrel, $page);
106 $plugins = array();
107 foreach ($p_node->data as $plugname => $plugentry)
108 {
109 //echo "cacheGetActive : examining $plugname (status {$plugentry['status']})<br/>\n";
110 if ($plugentry['status'] & PLUG_ACTIVE)
111 {
112 //echo "cacheGetActive : adding $plugname<br/>\n";
113 $plugins[$plugname] = $plugentry;
114 }
115 }
116 return $plugins;
117 }
118
119
120 /** Returns an array of cache entries representing the available plugins
121 * in a given context
122 *
123 * @param $cache
124 * @param $barrel
125 * @param $page
126 */
127 function cacheGetVisible($cache, $barrel, $page)
128 {
129 $p_node = $this->cacheGetPageNode($cache, $barrel, $page);
130 return $p_node->data;
131 }
132
133
134 /** Remove database references to plugins that are not available.
135 */
136 function clean_database(&$page)
137 {
138 /*
139 $res = $this->dbh->query("select distinct plugin from diogenes_plugin");
140 while (list($plugname) = mysql_fetch_row($res))
141 {
142 $page->info("examining $plugname..");
143 $plug = $this->load($plugname);
144 if (!is_object($plug)) {
145 $page->info("plugin $plugname is broken, removing");
146 $this->dbh->query("delete from diogenes_plugin where plugin='$plugname'");
147 }
148 }
149 mysql_free_result($res);
150 */
151 }
152
153
154 /** Build view for current level.
155 */
156 function compileNode($node, &$outparent, $index)
157 {
158 $outvals = array();
159 foreach ($outparent->data as $plugin => $parentval)
160 {
161 //echo "Processing plugin '$plugin' for &lt;{$node->name}&gt;<br/>\n";
162 $outval = '';
163 if (($parentval['status'] & PLUG_ACTIVE) || !($parentval['status'] & PLUG_LOCK))
164 {
165 //echo "* plugin '$plugin' not locked off parent level<br/>\n";
166 $outval = $parentval;
167 if ((is_array($node->data[$plugin])) && ($node->data[$plugin]['status'] & PLUG_SET))
168 {
169 //echo "** plugin set at current level<br/>\n";
170 $outval['params'] = $node->data[$plugin]['params'];
171 if (!($parentval['status'] & PLUG_LOCK)) {
172 //echo "*** plugin status set to DB-specified value<br/>\n";
173 $outval['status'] = $node->data[$plugin]['status'];
174 } else {
175 $outval['status'] = $parentval['status'];
176 }
177 } else {
178 //echo "** plugin unset at current level<br/>\n";
179 }
180 }
181
182 // add the plugin to output
183 if (is_array($outval))
184 {
185 $outvals[$plugin] = $outval;
186 }
187 }
188 $outnode = new Diogenes_Tree_Node($outvals, $node->name);
189 //echo "<hr/>";
190
191 // recurse into children
192 foreach ($node->children as $cindex => $child)
193 {
194 $this->compileNode($child, $outnode, $cindex);
195 }
196
197 // add the produced node
198 $outparent->setChild($index, $outnode);
199 }
200
201
202 /** Compile plugin cache.
203 *
204 * @param $barrel
205 */
206 function compileCache($barrel, &$caller)
207 {
208 $caller->info("Recompiling " .($barrel ? "plugin cache for barrel '$barrel'" : "global plugin cache"));
209
210 // get the list of all plugins present on the system
211 $allplugins = array();
212 $plugfiles = System::find($this->plugdir.' -type f -name *.php');
213 foreach ($plugfiles as $file) {
214 $name = basename($file);
215 $name = substr($name, 0, -4);
216 array_push($allplugins, $name);
217 }
218
219 $defcache = array();
220 // fill initial values
221 foreach ($allplugins as $plugin)
222 {
223 $plug_h = $this->load($plugin);
224 $defcache[$plugin] = $plug_h->toArray();
225 }
226
227 // get DB values
228 $dbcache = array();
229
230 $sql_limit = $barrel ? " where barrel='{$barrel}' or barrel=''" : "";
231 $sql = "select barrel, page, plugin, status, params from diogenes_plugin" . $sql_limit;
232 $res = $this->dbh->query($sql);
233 while($row = mysql_fetch_row($res))
234 {
235 $c_barrel = array_shift($row);
236 $c_page = array_shift($row);
237 $plugin = array_shift($row);
238 $plugentry = array(
239 'status' => $row[0],
240 'params' => ($row[1] ? var_decode_bin($row[1]) : array())
241 );
242 $plug_h = $this->load($plugin, $plugentry);
243 //echo "Got params from DB for '$plugin', barrel '$c_barrel', page '$c_page' : ".$row[2]."<br/>";
244 $dbcache[$c_barrel][$c_page][$plugin] = $plug_h->toArray();
245 }
246 mysql_free_result($res);
247
248 // build the input tree
249 $globals_node = new Diogenes_Tree_Node($dbcache[''][0], 'globals defaults');
250 $sql_limit = $barrel ? " where alias='{$barrel}'" : " where alias!=''";
251 $res = $this->dbh->query("select alias from diogenes_site" . $sql_limit);
252 while(list($c_barrel) = mysql_fetch_row($res))
253 {
254 $barrel_node = new Diogenes_Tree_Node($dbcache[$c_barrel][0], "barrel '$c_barrel' defaults");
255 $res2 = $this->dbh->query("select PID from {$c_barrel}_page");
256 while(list($page) = mysql_fetch_row($res2))
257 {
258 $page_node = new Diogenes_Tree_Node($dbcache[$c_barrel][$page], "barrel '$c_barrel' page $page");
259 $barrel_node->setChild($page, $page_node);
260 }
261 mysql_free_result($res2);
262 $globals_node->setChild($c_barrel, $barrel_node);
263 }
264 mysql_free_result($res);
265
266 // compile the cache
267 $top_out_node = new Diogenes_Tree_Node($defcache, 'plugin defaults');
268 $this->compileNode($globals_node, $top_out_node, 'globals');
269 $globals_out_node = $top_out_node->getChild('globals');
270 //echo "<pre>" . $top_out_node->dump() . "</pre><hr/>";
271
272 // produce dump(s)
273 if ($barrel) {
274 $dump_node = $globals_out_node->getChild($barrel);
275 $dump_node->writeFile($this->cachefile($barrel));
276 $dump_node->writeFile($this->cachefile($barrel).".txt", NODE_DUMP_TEXT);
277 } else {
278 $globals_out_node->writeFile($this->cachefile($barrel), NODE_DUMP_NOCHILDREN);
279 $globals_out_node->writeFile($this->cachefile($barrel).".txt", NODE_DUMP_NOCHILDREN | NODE_DUMP_TEXT);
280 foreach ($globals_out_node->children as $c_barrel => $dump_node)
281 {
282 $dump_node->writeFile($this->cachefile($c_barrel));
283 $dump_node->writeFile($this->cachefile($c_barrel).".txt", NODE_DUMP_TEXT);
284 }
285 }
286 }
287
288
289 /** Load the specified plugin
290 *
291 * @param $plugentry
292 */
293 function load($plugin, $plugentry = '')
294 {
295 $plugfile = $this->plugdir."/$plugin.php";
296 if (!file_exists($plugfile)) {
297 trigger_error("could not find plugin file '$plugfile'", E_USER_WARNING);
298 return;
299 }
300 include_once($plugfile);
301 if (!class_exists($plugin)) {
302 trigger_error("could not find class '$plugin'", E_USER_WARNING);
303 return;
304 }
305
306 // load and register plugin
307 $plug_h = new $plugin();
308 if (is_array($plugentry))
309 $plug_h->fromArray($plugentry);
310
311 return $plug_h;
312 }
313
314
315 /** Read the compiled plugin cache
316 *
317 * @param $cachefile
318 * @param $barrel
319 */
320 function readCache($cachefile, $barrel)
321 {
322 if (!file_exists($cachefile)) {
323 return array();
324 }
325
326 return Diogenes_Tree_Node::readFile($cachefile);
327 }
328
329
330 /** Prepare plugins trace for output
331 */
332 function trace_format()
333 {
334 $out = '<table class="light" style="width: 100%; font-family: monospace">'."\n";
335 $odd = 0;
336 foreach ($this->log as $key => $val)
337 {
338 $trclass = $odd ? ' class="odd"' : '';
339 $out .= "<tr><th colspan=\"2\">{$val['name']} v{$val['version']}</th></tr>\n";
340 $out .= "<tr><td>status</td><td>{$val['status']}</td></tr>\n";
341 $out .= "<tr$trclass><td>type</td><td>{$val['type']}</td></tr>\n";
342 $out .= "<tr$trclass><td>description</td><td>{$val['description']}</td></tr>\n";
343 if (!empty($val['params'])) {
344 $out .= "<tr$trclass><td>parameters</td><td>".var_encode_html($val['params'])."</td></tr>\n";
345 }
346 $odd = ($odd+1) % 2;
347 }
348 $out .= "</table>\n";
349 return $out;
350 }
351
352 }
353
354 ?>