1f94a8540c663f80c4c17f21f6947497a5c650c7
[diogenes.git] / include / phplayersmenu / layersmenu-common.inc.php
1 <?php
2 // PHP Layers Menu 3.1.1 (C) 2001-2003 Marco Pratesi (marco at telug dot it)
3
4 /**
5 * This file contains the code of the LayersMenuCommon class.
6 * @package PHPLayersMenu
7 */
8
9
10 /**
11 * This is the "common" class of the PHP Layers Menu library.
12 * @version 3.1.1
13 * @package PHPLayersMenu
14 */
15 class LayersMenuCommon {
16
17 /**
18 * The name of the package
19 * @access private
20 * @var string
21 */
22 var $_packageName;
23 /**
24 * The version of the package
25 * @access private
26 * @var string
27 */
28 var $version;
29 /**
30 * The copyright of the package
31 * @access private
32 * @var string
33 */
34 var $copyright;
35 /**
36 * The author of the package
37 * @access private
38 * @var string
39 */
40 var $author;
41
42 /**
43 * URL to be prepended to the menu hrefs
44 * @access private
45 * @var string
46 */
47 var $prependedUrl = "";
48 /**
49 * Do you want that code execution halts on error?
50 * @access private
51 * @var string
52 */
53 var $haltOnError = "yes";
54
55 /**
56 * The base directory where the package is installed
57 * @access private
58 * @var string
59 */
60 var $dirroot;
61 /**
62 * The "libjs" directory of the package
63 * @access private
64 * @var string
65 */
66 var $libjsdir;
67 /**
68 * The directory where images related to the menu can be found
69 * @access private
70 * @var string
71 */
72 var $imgdir;
73 /**
74 * The http path corresponding to imgdir
75 * @access private
76 * @var string
77 */
78 var $imgwww;
79 /**
80 * The directory where templates can be found
81 * @access private
82 * @var string
83 */
84 var $tpldir;
85 /**
86 * The string containing the menu structure
87 * @access private
88 * @var string
89 */
90 var $menuStructure;
91
92 /**
93 * It counts nodes for all menus
94 * @access private
95 * @var integer
96 */
97 var $_nodesCount;
98 /**
99 * A multi-dimensional array where we store informations for each menu entry
100 * @access private
101 * @var array
102 */
103 var $tree;
104 /**
105 * The maximum hierarchical level of menu items
106 * @access private
107 * @var integer
108 */
109 var $_maxLevel;
110 /**
111 * An array that counts the number of first level items for each menu
112 * @access private
113 * @var array
114 */
115 var $_firstLevelCnt;
116 /**
117 * An array containing the number identifying the first item of each menu
118 * @access private
119 * @var array
120 */
121 var $_firstItem;
122 /**
123 * An array containing the number identifying the last item of each menu
124 * @access private
125 * @var array
126 */
127 var $_lastItem;
128
129 /**
130 * Data Source Name: the connection string for PEAR DB
131 * @access private
132 * @var string
133 */
134 var $dsn = "pgsql://dbuser:dbpass@dbhost/dbname";
135 /**
136 * DB connections are either persistent or not persistent
137 * @access private
138 * @var boolean
139 */
140 var $persistent = false;
141 /**
142 * Name of the table storing data describing the menu
143 * @access private
144 * @var string
145 */
146 var $tableName = "phplayersmenu";
147 /**
148 * Name of the i18n table corresponding to $tableName
149 * @access private
150 * @var string
151 */
152 var $tableName_i18n = "phplayersmenu_i18n";
153 /**
154 * Names of fields of the table storing data describing the menu
155 *
156 * default field names correspond to the same field names foreseen
157 * by the menu structure format
158 *
159 * @access private
160 * @var array
161 */
162 var $tableFields = array(
163 "id" => "id",
164 "parent_id" => "parent_id",
165 "text" => "text",
166 "href" => "href",
167 "title" => "title",
168 "icon" => "icon",
169 "target" => "target",
170 "orderfield" => "orderfield",
171 "expanded" => "expanded"
172 );
173 /**
174 * Names of fields of the i18n table corresponding to $tableName
175 * @access private
176 * @var array
177 */
178 var $tableFields_i18n = array(
179 "language" => "language",
180 "id" => "id",
181 "text" => "text",
182 "title" => "title"
183 );
184 /**
185 * A temporary array to store data retrieved from the DB and to perform the depth-first search
186 * @access private
187 * @var array
188 */
189 var $_tmpArray = array();
190
191 /**
192 * The constructor method; it initializates the menu system
193 * @return void
194 */
195 function LayersMenuCommon() {
196
197 $this->_packageName = "PHP Layers Menu";
198 $this->version = "3.1.1";
199 $this->copyright = "(C) 2001-2003";
200 $this->author = "Marco Pratesi (marco at telug dot it)";
201
202 $this->prependedUrl = "";
203
204 $this->dirroot = "./";
205 $this->libjsdir = "./libjs/";
206 $this->imgdir = "./images/";
207 $this->imgwww = "images/";
208 $this->tpldir = "./templates/";
209 $this->menuStructure = "";
210 $this->separator = "|";
211
212 $this->_nodesCount = 0;
213 $this->tree = array();
214 $this->_maxLevel = array();
215 $this->_firstLevelCnt = array();
216 $this->_firstItem = array();
217 $this->_lastItem = array();
218 }
219
220 /**
221 * The method to set the prepended URL
222 * @access public
223 * @return boolean
224 */
225 function setPrependedUrl($prependedUrl) {
226 // We do not perform any check
227 $this->prependedUrl = $prependedUrl;
228 return true;
229 }
230
231 /**
232 * The method to set the dirroot directory
233 * @access public
234 * @return boolean
235 */
236 function setDirrootCommon($dirroot) {
237 if (!is_dir($dirroot)) {
238 $this->error("setDirroot: $dirroot is not a directory.");
239 return false;
240 }
241 if (substr($dirroot, -1) != "/") {
242 $dirroot .= "/";
243 }
244 $oldlength = strlen($this->dirroot);
245 $foobar = strpos($this->libjsdir, $this->dirroot);
246 if (!($foobar === false || $foobar != 0)) {
247 $this->libjsdir = $dirroot . substr($this->libjsdir, $oldlength);
248 }
249 $foobar = strpos($this->imgdir, $this->dirroot);
250 if (!($foobar === false || $foobar != 0)) {
251 $this->imgdir = $dirroot . substr($this->imgdir, $oldlength);
252 }
253 $foobar = strpos($this->tpldir, $this->dirroot);
254 if (!($foobar === false || $foobar != 0)) {
255 $this->tpldir = $dirroot . substr($this->tpldir, $oldlength);
256 }
257 $this->dirroot = $dirroot;
258 return true;
259 }
260
261 /**
262 * The method to set the libjsdir directory
263 * @access public
264 * @return boolean
265 */
266 function setLibjsdir($libjsdir) {
267 if ($libjsdir != "" && substr($libjsdir, -1) != "/") {
268 $libjsdir .= "/";
269 }
270 if ($libjsdir == "" || substr($libjsdir, 0, 1) != "/") {
271 $foobar = strpos($libjsdir, $this->dirroot);
272 if ($foobar === false || $foobar != 0) {
273 $libjsdir = $this->dirroot . $libjsdir;
274 }
275 }
276 if (!is_dir($libjsdir)) {
277 $this->error("setLibjsdir: $libjsdir is not a directory.");
278 return false;
279 }
280 $this->libjsdir = $libjsdir;
281 return true;
282 }
283
284 /**
285 * The method to set the imgdir directory
286 * @access public
287 * @return boolean
288 */
289 function setImgdir($imgdir) {
290 if ($imgdir != "" && substr($imgdir, -1) != "/") {
291 $imgdir .= "/";
292 }
293 if ($imgdir == "" || substr($imgdir, 0, 1) != "/") {
294 $foobar = strpos($imgdir, $this->dirroot);
295 if ($foobar === false || $foobar != 0) {
296 $imgdir = $this->dirroot . $imgdir;
297 }
298 }
299 if (!is_dir($imgdir)) {
300 $this->error("setImgdir: $imgdir is not a directory.");
301 return false;
302 }
303 $this->imgdir = $imgdir;
304 return true;
305 }
306
307 /**
308 * The method to set imgwww
309 * @access public
310 * @return void
311 */
312 function setImgwww($imgwww) {
313 if ($imgwww != "" && substr($imgwww, -1) != "/") {
314 $imgwww .= "/";
315 }
316 $this->imgwww = $imgwww;
317 }
318
319 /**
320 * The method to set the tpldir directory
321 * @access public
322 * @return boolean
323 */
324 function setTpldirCommon($tpldir) {
325 if ($tpldir != "" && substr($tpldir, -1) != "/") {
326 $tpldir .= "/";
327 }
328 if ($tpldir == "" || substr($tpldir, 0, 1) != "/") {
329 $foobar = strpos($tpldir, $this->dirroot);
330 if ($foobar === false || $foobar != 0) {
331 $tpldir = $this->dirroot . $tpldir;
332 }
333 }
334 if (!is_dir($tpldir)) {
335 $this->error("setTpldir: $tpldir is not a directory.");
336 return false;
337 }
338 $this->tpldir = $tpldir;
339 return true;
340 }
341
342 /**
343 * The method to read the menu structure from a file
344 * @access public
345 * @param string $tree_file the menu structure file
346 * @return boolean
347 */
348 function setMenuStructureFile($tree_file) {
349 if (!($fd = fopen($tree_file, "r"))) {
350 $this->error("setMenuStructureFile: unable to open file $tree_file.");
351 return false;
352 }
353 $this->menuStructure = "";
354 while ($buffer = fgets($fd, 4096)) {
355 $buffer = ereg_replace(chr(13), "", $buffer); // Microsoft Stupidity Suppression
356 $this->menuStructure .= $buffer;
357 }
358 fclose($fd);
359 if ($this->menuStructure == "") {
360 $this->error("setMenuStructureFile: $tree_file is empty.");
361 return false;
362 }
363 return true;
364 }
365
366 /**
367 * The method to set the menu structure passing it through a string
368 * @access public
369 * @param string $tree_string the menu structure string
370 * @return boolean
371 */
372 function setMenuStructureString($tree_string) {
373 $this->menuStructure = ereg_replace(chr(13), "", $tree_string); // Microsoft Stupidity Suppression
374 if ($this->menuStructure == "") {
375 $this->error("setMenuStructureString: empty string.");
376 return false;
377 }
378 return true;
379 }
380
381 /**
382 * The method to set the value of separator
383 * @access public
384 * @return void
385 */
386 function setSeparator($separator) {
387 $this->separator = $separator;
388 }
389
390 /**
391 * The method to set parameters for the DB connection
392 * @access public
393 * @param string $dns Data Source Name: the connection string for PEAR DB
394 * @param bool $persistent DB connections are either persistent or not persistent
395 * @return boolean
396 */
397 function setDBConnParms($dsn, $persistent=false) {
398 if (!is_string($dsn)) {
399 $this->error("initdb: \$dsn is not an string.");
400 return false;
401 }
402 if (!is_bool($persistent)) {
403 $this->error("initdb: \$persistent is not a boolean.");
404 return false;
405 }
406 $this->dsn = $dsn;
407 $this->persistent = $persistent;
408 return true;
409 }
410
411 /**
412 * The method to set the name of the table storing data describing the menu
413 * @access public
414 * @param string
415 * @return boolean
416 */
417 function setTableName($tableName) {
418 if (!is_string($tableName)) {
419 $this->error("setTableName: \$tableName is not a string.");
420 return false;
421 }
422 $this->tableName = $tableName;
423 return true;
424 }
425
426 /**
427 * The method to set the name of the i18n table corresponding to $tableName
428 * @access public
429 * @param string
430 * @return boolean
431 */
432 function setTableName_i18n($tableName_i18n) {
433 if (!is_string($tableName_i18n)) {
434 $this->error("setTableName_i18n: \$tableName_i18n is not a string.");
435 return false;
436 }
437 $this->tableName_i18n = $tableName_i18n;
438 return true;
439 }
440
441 /**
442 * The method to set names of fields of the table storing data describing the menu
443 * @access public
444 * @param array
445 * @return boolean
446 */
447 function setTableFields($tableFields) {
448 if (!is_array($tableFields)) {
449 $this->error("setTableFields: \$tableFields is not an array.");
450 return false;
451 }
452 if (count($tableFields) == 0) {
453 $this->error("setTableFields: \$tableFields is a zero-length array.");
454 return false;
455 }
456 reset ($tableFields);
457 while (list($key, $value) = each($tableFields)) {
458 $this->tableFields[$key] = ($value == "") ? "''" : $value;
459 }
460 return true;
461 }
462
463 /**
464 * The method to set names of fields of the i18n table corresponding to $tableName
465 * @access public
466 * @param array
467 * @return boolean
468 */
469 function setTableFields_i18n($tableFields_i18n) {
470 if (!is_array($tableFields_i18n)) {
471 $this->error("setTableFields_i18n: \$tableFields_i18n is not an array.");
472 return false;
473 }
474 if (count($tableFields_i18n) == 0) {
475 $this->error("setTableFields_i18n: \$tableFields_i18n is a zero-length array.");
476 return false;
477 }
478 reset ($tableFields_i18n);
479 while (list($key, $value) = each($tableFields_i18n)) {
480 $this->tableFields_i18n[$key] = ($value == "") ? "''" : $value;
481 }
482 return true;
483 }
484
485 /**
486 * The method to parse the current menu structure and correspondingly update related variables
487 * @access public
488 * @param string $menu_name the name to be attributed to the menu
489 * whose structure has to be parsed
490 * @return void
491 */
492 function parseStructureForMenu(
493 $menu_name = "" // non consistent default...
494 ) {
495 $this->_maxLevel[$menu_name] = 0;
496 $this->_firstLevelCnt[$menu_name] = 0;
497 $this->_firstItem[$menu_name] = $this->_nodesCount + 1;
498 $cnt = $this->_firstItem[$menu_name];
499 $menuStructure = $this->menuStructure;
500
501 /* *********************************************** */
502 /* Partially based on a piece of code taken from */
503 /* TreeMenu 1.1 - Bjorge Dijkstra (bjorge@gmx.net) */
504 /* *********************************************** */
505
506 while ($menuStructure != "") {
507 $before_cr = strcspn($menuStructure, "\n");
508 $buffer = substr($menuStructure, 0, $before_cr);
509 $menuStructure = substr($menuStructure, $before_cr+1);
510 if (substr($buffer, 0, 1) != "#") { // non commented item line...
511 $tmp = rtrim($buffer);
512 $node = explode($this->separator, $tmp);
513 for ($i=count($node); $i<=6; $i++) {
514 $node[$i] = "";
515 }
516 $this->tree[$cnt]["level"] = strlen($node[0]);
517 $this->tree[$cnt]["text"] = $node[1];
518 $this->tree[$cnt]["href"] = $node[2];
519 $this->tree[$cnt]["title"] = $node[3];
520 $this->tree[$cnt]["icon"] = $node[4];
521 $this->tree[$cnt]["target"] = $node[5];
522 $this->tree[$cnt]["expanded"] = $node[6];
523 $cnt++;
524 }
525 }
526
527 /* *********************************************** */
528
529 $this->_lastItem[$menu_name] = count($this->tree);
530 $this->_nodesCount = $this->_lastItem[$menu_name];
531 $this->tree[$this->_lastItem[$menu_name]+1]["level"] = 0;
532 $this->_postParse($menu_name);
533 }
534
535 /**
536 * The method to parse the current menu table and correspondingly update related variables
537 * @access public
538 * @param string $menu_name the name to be attributed to the menu
539 * whose structure has to be parsed
540 * @param string $language i18n language; either omit it or pass
541 * an empty string ("") if you do not want to use any i18n table
542 * @return void
543 */
544 function scanTableForMenu(
545 $menu_name = "", // non consistent default...
546 $language = ""
547 ) {
548 $this->_maxLevel[$menu_name] = 0;
549 $this->_firstLevelCnt[$menu_name] = 0;
550 unset($this->tree[$this->_nodesCount+1]);
551 $this->_firstItem[$menu_name] = $this->_nodesCount + 1;
552 /* BEGIN BENCHMARK CODE
553 $time_start = $this->_getmicrotime();
554 /* END BENCHMARK CODE */
555 $db = DB::connect($this->dsn, $this->persistent);
556 if (DB::isError($db)) {
557 $this->error("scanTableForMenu: " . $db->getMessage());
558 }
559 $dbresult = $db->query("
560 SELECT " .
561 $this->tableFields["id"] . " AS id, " .
562 $this->tableFields["parent_id"] . " AS parent_id, " .
563 $this->tableFields["text"] . " AS text, " .
564 $this->tableFields["href"] . " AS href, " .
565 $this->tableFields["title"] . " AS title, " .
566 $this->tableFields["icon"] . " AS icon, " .
567 $this->tableFields["target"] . " AS target, " .
568 $this->tableFields["expanded"] . " AS expanded
569 FROM " . $this->tableName . "
570 WHERE " . $this->tableFields["id"] . " <> 1
571 ORDER BY " . $this->tableFields["orderfield"] . ", " . $this->tableFields["text"] . " ASC
572 ");
573 $this->_tmpArray = array();
574 while ($dbresult->fetchInto($row, DB_FETCHMODE_ASSOC)) {
575 $this->_tmpArray[$row["id"]]["parent_id"] = $row["parent_id"];
576 $this->_tmpArray[$row["id"]]["text"] = $row["text"];
577 $this->_tmpArray[$row["id"]]["href"] = $row["href"];
578 $this->_tmpArray[$row["id"]]["title"] = $row["title"];
579 $this->_tmpArray[$row["id"]]["icon"] = $row["icon"];
580 $this->_tmpArray[$row["id"]]["target"] = $row["target"];
581 $this->_tmpArray[$row["id"]]["expanded"] = $row["expanded"];
582 }
583 if ($language != "") {
584 $dbresult = $db->query("
585 SELECT " .
586 $this->tableFields_i18n["id"] . " AS id, " .
587 $this->tableFields_i18n["text"] . " AS text, " .
588 $this->tableFields_i18n["title"] . " AS title
589 FROM " . $this->tableName_i18n . "
590 WHERE " . $this->tableFields_i18n["id"] . " <> 1
591 AND " . $this->tableFields_i18n["language"] . " = '$language'
592 ");
593 while ($dbresult->fetchInto($row, DB_FETCHMODE_ASSOC)) {
594 $this->_tmpArray[$row["id"]]["text"] = $row["text"];
595 $this->_tmpArray[$row["id"]]["title"] = $row["title"];
596 }
597 }
598 unset($dbresult);
599 unset($row);
600 $this->_depthFirstSearch($this->_tmpArray, $menu_name, 1, 1);
601 /* BEGIN BENCHMARK CODE
602 $time_end = $this->_getmicrotime();
603 $time = $time_end - $time_start;
604 print "TIME ELAPSED = " . $time . "\n<br>";
605 /* END BENCHMARK CODE */
606 $this->_lastItem[$menu_name] = count($this->tree);
607 $this->_nodesCount = $this->_lastItem[$menu_name];
608 $this->tree[$this->_lastItem[$menu_name]+1]["level"] = 0;
609 $this->_postParse($menu_name);
610 }
611
612 function _getmicrotime() {
613 list($usec, $sec) = explode(" ", microtime());
614 return ((float) $usec + (float) $sec);
615 }
616
617 /**
618 * Recursive method to perform the depth-first search of the tree data taken from the current menu table
619 * @access private
620 * @param array $tmpArray the temporary array that stores data to perform
621 * the depth-first search
622 * @param string $menu_name the name to be attributed to the menu
623 * whose structure has to be parsed
624 * @param integer $parent_id id of the item whose children have
625 * to be searched for
626 * @param integer $level the hierarchical level of children to be searched for
627 * @return void
628 */
629 function _depthFirstSearch($tmpArray, $menu_name, $parent_id=1, $level) {
630 reset ($tmpArray);
631 while (list($id, $foobar) = each($tmpArray)) {
632 if ($foobar["parent_id"] == $parent_id) {
633 unset($tmpArray[$id]);
634 unset($this->_tmpArray[$id]);
635 $cnt = count($this->tree) + 1;
636 $this->tree[$cnt]["level"] = $level;
637 $this->tree[$cnt]["text"] = $foobar["text"];
638 $this->tree[$cnt]["href"] = $foobar["href"];
639 $this->tree[$cnt]["title"] = $foobar["title"];
640 $this->tree[$cnt]["icon"] = $foobar["icon"];
641 $this->tree[$cnt]["target"] = $foobar["target"];
642 $this->tree[$cnt]["expanded"] = $foobar["expanded"];
643 unset($foobar);
644 if ($id != $parent_id) {
645 $this->_depthFirstSearch($this->_tmpArray, $menu_name, $id, $level+1);
646 }
647 }
648 }
649 }
650
651 /**
652 * A method providing parsing needed after both file/string parsing and DB table parsing
653 * @access private
654 * @param string $menu_name the name of the menu for which the parsing
655 * has to be performed
656 * @return void
657 */
658 function _postParse(
659 $menu_name = "" // non consistent default...
660 ) {
661 for ($cnt=$this->_firstItem[$menu_name]; $cnt<=$this->_lastItem[$menu_name]; $cnt++) { // this counter scans all nodes of the new menu
662 $this->tree[$cnt]["child_of_root_node"] = ($this->tree[$cnt]["level"] == 1);
663 $this->tree[$cnt]["parsed_text"] = stripslashes($this->tree[$cnt]["text"]);
664 $this->tree[$cnt]["parsed_href"] = (ereg_replace(" ", "", $this->tree[$cnt]["href"]) == "") ? "#" : $this->prependedUrl . $this->tree[$cnt]["href"];
665 $this->tree[$cnt]["parsed_title"] = ($this->tree[$cnt]["title"] == "") ? "" : " title=\"" . addslashes($this->tree[$cnt]["title"]) . "\"";
666 $fooimg = $this->imgdir . $this->tree[$cnt]["icon"];
667 if ($this->tree[$cnt]["icon"] == "" || !(file_exists($fooimg))) {
668 $this->tree[$cnt]["parsed_icon"] = "";
669 } else {
670 $this->tree[$cnt]["parsed_icon"] = $this->tree[$cnt]["icon"];
671 $foobar = getimagesize($fooimg);
672 $this->tree[$cnt]["iconwidth"] = $foobar[0];
673 $this->tree[$cnt]["iconheight"] = $foobar[1];
674 }
675 $this->tree[$cnt]["parsed_target"] = ($this->tree[$cnt]["target"] == "") ? "" : " target=\"" . $this->tree[$cnt]["target"] . "\"";
676 // $this->tree[$cnt]["expanded"] = ($this->tree[$cnt]["expanded"] == "") ? 0 : $this->tree[$cnt]["expanded"];
677 $this->_maxLevel[$menu_name] = max($this->_maxLevel[$menu_name], $this->tree[$cnt]["level"]);
678 if ($this->tree[$cnt]["level"] == 1) {
679 $this->_firstLevelCnt[$menu_name]++;
680 }
681 }
682 }
683
684 /**
685 * Method to handle errors
686 * @access private
687 * @param string $errormsg the error message
688 * @return void
689 */
690 function error($errormsg) {
691 print "<b>LayersMenu Error:</b> " . $errormsg . "<br />\n";
692 if ($this->haltOnError == "yes") {
693 die("<b>Halted.</b><br />\n");
694 }
695 }
696
697 } /* END OF CLASS */
698
699 ?>