more work on the plugins system
[diogenes.git] / include / Barrel.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 require_once 'Barrel/Page.php';
22 require_once 'Barrel/Options.php';
23 require_once 'diogenes/diogenes.flagset.inc.php';
24 require_once 'Plugin/Skel.php';
25
26
27 /** This class describes a Diogenes Barrel.
28 */
29 class Diogenes_Barrel
30 {
31 /** The barrel's alias. */
32 var $alias;
33
34 /** The database table holding the menus */
35 var $table_menu;
36
37 /** The database table holding the pages */
38 var $table_page;
39
40 /** The site's flags. */
41 var $flags;
42
43 /** The site's options. */
44 var $options;
45
46 /** Cache of the homepage ID */
47 var $homepage;
48
49 /** Handle to the spool */
50 var $spool;
51
52 /** If the barrel is running on a virtualhost. */
53 var $vhost;
54
55 /** Cache of tree */
56 var $treeCache;
57
58 /** File containing the tree cache. */
59 var $treeCacheFile;
60
61 /** Cache of the plugins */
62 var $pluginsCache;
63
64 /** File containing the plugin cache. */
65 var $pluginsCacheFile;
66
67
68 /** Construct a Diogenes Barrel.
69 *
70 * @param $alias
71 */
72 function Diogenes_Barrel($alias)
73 {
74 global $globals;
75 $webdav = '';
76
77 // Retrieve site-wide info from database
78 $res = $globals->db->query("select alias,vhost,flags from diogenes_site where alias='$alias'");
79 if (!list($this->alias,$this->vhost,$flags) = mysql_fetch_row($res)) {
80 return;
81 }
82 mysql_free_result($res);
83
84 $this->table_menu = "{$this->alias}_menu";
85 $this->table_page = "{$this->alias}_page";
86 $this->treeCacheFile = $globals->spoolroot."/diogenes_c/". $this->alias.".tree";
87 $this->pluginsCacheFile = $globals->plugins->cacheFile($this->alias);
88
89 $this->flags = new flagset($flags);
90 $this->options = new Diogenes_Barrel_Options($this->alias);
91 $this->spool = new DiogenesSpool($this,$this->alias);
92
93 $this->readTree();
94 }
95
96
97 /** Create a new Diogenes barrel. This creates the database, RCS and
98 * spool entries for the new barrel.
99 *
100 * @param $alias
101 * @param $caller
102 */
103 function create($alias, &$caller)
104 {
105 global $globals;
106
107 /* sanity check */
108 if (!preg_match("/^[a-zA-Z0-9_]+$/",$alias) or
109 in_array($alias, $globals->invalidaliases))
110 {
111 $caller->info("Invalid barrel name!");
112 return;
113 }
114
115 $res = $globals->db->query("select alias from diogenes_site where alias='$alias'");
116 if (mysql_num_rows($res) > 0) {
117 $caller->info("Entry '{$alias}' already exists in table 'diogenes_site'!");
118 return;
119 }
120
121 if (file_exists("{$globals->rcsroot}/$alias")) {
122 $caller->info("Directory '{$globals->rcsroot}/$alias' already exists!");
123 return;
124 }
125
126 if (!is_dir($globals->rcsroot) || !is_writable($globals->rcsroot)) {
127 $caller->info("Directory '{$globals->rcsroot}' is not writable!");
128 return;
129 }
130
131 /* log this event */
132 $caller->log("barrel_create","$alias:*");
133
134 /* create DB entry */
135 $globals->db->query("insert into diogenes_site set alias='$alias'");
136
137 $globals->db->query("CREATE TABLE {$alias}_menu ("
138 . "MID int(10) unsigned NOT NULL auto_increment,"
139 . "MIDpere int(10) unsigned NOT NULL,"
140 . "ordre int(10) unsigned NOT NULL,"
141 . "title tinytext NOT NULL,"
142 . "link text NOT NULL,"
143 . "PID int(10) unsigned NOT NULL,"
144 . "PRIMARY KEY (MID)"
145 . ") TYPE=MyISAM;");
146
147 $globals->db->query("CREATE TABLE {$alias}_page ("
148 . "PID int(10) unsigned NOT NULL auto_increment,"
149 . "parent INT( 10 ) UNSIGNED NOT NULL default '0',"
150 . "location tinytext NOT NULL,"
151 . "title tinytext NOT NULL,"
152 . "status tinyint(1) unsigned NOT NULL default '0',"
153 . "perms enum('public','auth','user','admin','forbidden') NOT NULL default 'public',"
154 . "wperms enum('public','auth','user','admin','forbidden') NOT NULL default 'admin',"
155 . "template varchar(255) NOT NULL,"
156 . "PRIMARY KEY (PID)"
157 . ") TYPE=MyISAM;");
158
159 /* set the barrel's title */
160 $opt = new Diogenes_Barrel_Options($alias);
161 $opt->updateOption('title',$alias);
162
163 /* create entry for the homepage */
164 $globals->db->query("insert into {$alias}_page set location='temp'");
165 $homepage = mysql_insert_id();
166 $globals->db->query("update {$alias}_page set location='',title='Home',perms='public' where PID='$homepage'");
167
168 /* create home page & copy CSS template */
169 $rcs = new $globals->rcs($caller,$alias,$_SESSION['session']->username,true);
170 $rcs->newdir("",$homepage);
171 $rcs->commit($homepage,$globals->htmlfile,"");
172 $rcs->commit($homepage,$globals->cssfile,
173 file_get_contents("{$globals->root}/{$globals->cssfile}") );
174 }
175
176
177 /** Destroy a Diogenes barrel. This removes the related database, RCS
178 * and spool entries.
179 *
180 * @param $alias
181 * @param $caller
182 */
183 function destroy($alias, &$caller) {
184 global $globals;
185
186 /** Sanity check */
187 if (!$alias) {
188 $caller->info("Empty alias supplied!");
189 return;
190 }
191
192 /* log this event */
193 $caller->log("barrel_delete","$alias:*");
194
195 system(escapeshellcmd("rm -rf ".escapeshellarg("{$globals->spoolroot}/$alias")));
196 system(escapeshellcmd("rm -rf ".escapeshellarg("{$globals->rcsroot}/$alias")));
197 system(escapeshellcmd("rm -f ".escapeshellarg("{$globals->spoolroot}/diogenes_c/$alias.tree")));
198 system(escapeshellcmd("rm -f ".escapeshellarg($globals->plugins->cacheFile($alias))));
199 $globals->db->query("drop table {$alias}_menu");
200 $globals->db->query("drop table {$alias}_page");
201 $globals->db->query("delete from diogenes_perm where alias='$alias'");
202 $globals->db->query("delete from diogenes_site where alias='$alias'");
203 $globals->db->query("delete from diogenes_option where barrel='$alias'");
204 $globals->db->query("delete from diogenes_plugin where barrel='$alias'");
205 }
206
207
208 /** Return the location corresponding to a given page ID
209 *
210 * @param $PID
211 */
212 function getLocation($PID)
213 {
214 return array_search($PID, $this->treeCache);
215 }
216
217
218
219 /** Return all the barrel's pages.
220 */
221 function getPages()
222 {
223 global $globals;
224 $bpages = array();
225
226 $res = $globals->db->query("select * from {$this->table_page}");
227 while ($props = mysql_fetch_assoc($res)) {
228 $bpages[$props['PID']] = new Diogenes_Barrel_Page($this, $props);
229 }
230 mysql_free_result($res);
231 return $bpages;
232 }
233
234
235 /** Return the page ID matching a given directory location
236 *
237 * @param $dir
238 */
239 function getPID($dir)
240 {
241 if (isset($this->treeCache[$dir]))
242 return $this->treeCache[$dir];
243 else
244 return;
245 }
246
247
248 /** Check whether the barrel has a given flag
249 *
250 * @param $flag
251 */
252 function hasFlag($flag)
253 {
254 return $this->flags->hasFlag($flag);
255 }
256
257
258 /** Compile the directory tree
259 */
260 function compileTree()
261 {
262 global $globals;
263
264 if (!$fp = fopen($this->treeCacheFile, "w")) {
265 trigger_error("failed to open '{$this->treeCacheFile}' for writing", E_USER_ERROR);
266 return;
267 }
268
269 // load all the pages
270 $res = $globals->db->query("select * from {$this->table_page}");
271 $tpages = array();
272 while ($props = mysql_fetch_assoc($res))
273 {
274 $tpage = new Diogenes_Barrel_Page($this, $props);
275 $tpages[$props['PID']] = $tpage;
276 if (!strlen($props['location']))
277 {
278 $homepage = $props['PID'];
279 }
280 }
281
282 // recursively build the tree, starting at the homepage
283 $str = $this->compilePageTree($tpages, $homepage, '');
284 fputs($fp, $str);
285 fclose($fp);
286 }
287
288
289 /** Compile a single page
290 */
291 function compilePageTree(&$tpages, $PID, $ploc)
292 {
293 global $globals;
294
295 $cpage = $tpages[$PID];
296 $ploc = ($ploc ? "$ploc/" : "") . $cpage->props['location'];
297
298 // add this page
299 $out = "$ploc\t$PID\t".$cpage->props['parent']."\n";
300
301 // add children
302 $res = $globals->db->query("select PID from {$this->table_page} where parent='$PID'");
303 while (list($child) = mysql_fetch_row($res))
304 {
305 $out .= $this->compilePageTree($tpages, $child, $ploc);
306 }
307 mysql_free_result($res);
308 return $out;
309 }
310
311
312 /** Load all active plugins for the specified page.
313 *
314 * @param $bpage
315 */
316 function loadPlugins(&$bpage)
317 {
318 global $globals;
319
320 $plugins = $globals->plugins->cacheGetActive($this->pluginsCache, $this->alias, $page);
321 $loaded = array();
322 foreach ($plugins as $plugname => $plugentry)
323 {
324 $loaded[$plugname] =& $globals->plugins->load($plugname, $plugentry);
325 }
326 return $loaded;
327 }
328
329
330 /** Read the compiled plugin cache
331 */
332 function readPlugins()
333 {
334 global $globals;
335
336 $this->pluginsCache = $globals->plugins->readCache($this->pluginsCacheFile, $this->alias);
337 }
338
339
340 /** Read the compiled directory tree
341 */
342 function readTree()
343 {
344 global $globals;
345
346 // if the tree cache does not exits, try to init it
347 if (!file_exists($this->treeCacheFile)) {
348 $this->compileTree();
349 }
350
351 if (!$fp = fopen($this->treeCacheFile, "r")) {
352 trigger_error("failed to open '{$this->treeCacheFile}' for reading", E_USER_ERROR);
353 return;
354 }
355
356 $locations = array();
357 while ($line = fgets($fp))
358 {
359 $line = substr($line, 0, -1);
360 $bits = explode("\t", $line);
361 list($loc, $pid, $parent) = $bits;
362 $locations[$loc] = $pid;
363 }
364 fclose($fp);
365
366 $this->treeCache = $locations;
367 }
368
369 }