Rekursives Baummenü mit MySQL
Auf der folgenden Seite wird das Script beschrieben, welches neuerdings als Hauptmenü auf sim4000.de eingesetzt wird.
Das Script besteht aus einer Klasse und einer MySQL Tabelle. Beides kann so kopiert werden und ist als Beispiel sofort lauffähig.
MySQL Tabelle
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | -- -- Tabellenstruktur für Tabelle `content` -- CREATE TABLE IF NOT EXISTS `content` ( `cid` int(11) NOT NULL auto_increment, `parent` int(11) NOT NULL, `corder` int(11) NOT NULL default '0', `nav_title` varchar(255) character set utf8 NOT NULL, PRIMARY KEY (`cid`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci; -- -- Daten für Tabelle `content` -- INSERT INTO `content` (`cid`, `parent`, `corder`, `nav_title`) VALUES (44, 43, 10, 'Farbwähler'), (43, 0, 90, 'Java'), (12, 0, 60, 'Home'), (13, 0, 190, 'Impressum'), (39, 0, 110, 'Nintendo DS'), (40, 39, 20, 'M3 Real Perfect'), (41, 39, 10, 'dsLinux'), (42, 39, 30, 'Videos on M3 Real'), (38, 0, 130, 'Login'), (45, 43, 50, 'verkettete Listen'), (46, 43, 40, 'MySQL Class'), (47, 43, 30, 'SQL Glaskugel'), (48, 56, 40, 'Apache'), (49, 48, 30, 'Eigene Fehlerseiten'), (50, 48, 20, 'mod_rewrite'), (52, 0, 80, 'PHP'), (53, 52, 100, 'Blätterfunktion'), (54, 52, 90, 'Captchas'), (55, 39, 40, 'NDS Headset'), (56, 0, 100, 'Linux'), (57, 56, 20, 'Bash'), (58, 57, 60, 'MySQL Backup via SSH'), (59, 0, 140, 'Sitemap'), (61, 56, 60, 'SMB Mount'), (62, 52, 80, 'MySQL Class'), (63, 52, 40, 'Website V3'), (64, 0, 150, 'RSS'), (65, 57, 40, 'Screenshots'), (66, 57, 30, 'Bash Prompt'), (67, 0, 120, 'Ebay'), (68, 67, 20, 'AcerNote 760i'), (77, 74, 50, 'Projekte'), (78, 74, 110, 'RSS Feeds'), (79, 52, 50, 'RSS Writer'), (71, 56, 70, 'SSH RSA Keys'), (72, 57, 20, 'Bash Banner'), (73, 57, 10, 'Bash Login'), (74, 0, 70, 'Blog'), (75, 74, 90, 'Sonstiges'), (76, 74, 10, 'Allgemein'), (80, 74, 20, 'Privat'), (81, 74, 130, 'Blogroll'), (82, 52, 60, 'Valid URL'), (83, 52, 70, 'Valid Email'), (84, 56, 30, 'OpenVPN'), (85, 74, 120, 'Tag Cloud'), (86, 67, 10, 'Jenoptik JD 12'), (87, 74, 40, 'Linux'), (88, 0, 180, 'Link me'), (89, 56, 10, 'Perl'), (90, 89, 10, 'MySQL Backup'), (91, 48, 10, 'mehrere Domains'), (92, 57, 50, 'Split vHost Logs'), (93, 56, 50, 'Cron Emails'), (94, 74, 30, 'Job'), (95, 74, 70, 'Programmieren'), (96, 56, 80, 'Terminal mit Tabs'), (97, 52, 20, 'Smilies'), (98, 43, 20, 'Passwort Generator'), (99, 74, 60, 'Technik'), (108, 0, 170, 'Gästebuch'), (107, 74, 100, 'Politik'), (109, 0, 160, 'Links'), (110, 52, 30, 'Besucherstatistik'), (111, 52, 10, 'foooooooo'); |
Das Script arbeitet mit einer MySQL Tabelle auf Rekursiver Basis. Der Baum wird also nach dem Eltern-Kind Prinzip gebildet. Das sieht dann wie folgt aus:
| ID | Parent | Name |
| 1 | 0 | Ebene 1 |
| 2 | 1 | Ebene 2 Eintrag 1 |
| 3 | 1 | Ebene 2 Eintrag 2 |
| 4 | 3 | Ebene 3 |
Nach dem Auslesen sieht der Baum dann so aus:
'- Ebene 1 |- Ebene2 Eintrag 1 | '- Ebene 3 '- Ebene 2 Eintrag 2
In der richtigen MySQL Tabelle ist zusätzlich noch eine Sortierspalte enthalten, um die Einträge in die richtige Reihenfolge zu bringen.
Beispiel Script
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | /*** * Config */ $sql['host'] = "localhost"; // MySQL Host $sql['user'] = "root"; // MySQL Username $sql['pass'] = "toor"; // MySQL Password $sql['data'] = "test"; // MySQL Database /*** * Treemenu Function */ class treeMenu { private $connection; private $database; private $enc; static $counter = 0; private $cid; /** * @param int $cid Aktuell aufgerufene Seite */ function __construct($cid) { if(!$cid || !is_numeric($cid)) $this->cid=0; else $this->cid=$cid; $this->connection = false; $this->database = false; } /***************** Datenbankverbindung *********************************/ /** * Verbindung herstellen * @param host Hostname des mysql Servers * @param user Benutzername * @param password Passwort zum Benutzer * @param database Zu benutzende Datenbank * @param enc Zeichenkodierung */ function mysqlConnect($host, $user, $password, $database, $enc) { if($this->connection) $this->mysqlDisconnect(); $this->connection = @mysql_connect($host, $user, $password) or die(mysql_error()); if($this->connection) { $this->enc=$enc; if($this->database = @mysql_select_db($database, $this->connection)) { @mysql_query("SET NAMES '".$enc."'"); return true; } } return false; } /** * mySQL Statement absetzen * @param query MySQL Statement * @return ResultSet des Statements */ function mysqlQuery($query, $die=true) { $result = mysql_query($query); if(mysql_errno($this->connection)) { if($die) die(mysql_errno($this->connection).": ".mysql_error($this->connection)); } return $result; } /** * Liefert das result eines Statements in einem 2 Dimensionalen Array * @param query MySQL Statement * @return Array[][] result */ function mysqlArray($query) { $i=0; $array = array(); $result = $this->mysqlQuery($query); while($row=mysql_fetch_row($result)) { for($j=0; $j<sizeof($row); $j++) { $array[$i][@mysql_field_name($result, $j)] = $row[$j]; } $i++; } $return[0] = mysql_num_rows($result); $return[1] = mysql_num_fields($result); $return[2] = $array; return $return; } /** * Verkuerzte Version von mysql_real_escape_string() * @param query Wert zum Escapen * @return der Escaped String */ function sqlij($string) { if(get_magic_quotes_gpc()==0) { return mysql_real_escape_string($string); } else { return $string; } } /***************************** Treemenu ***************************/ function getTreemenu($firstcall=false, $parent=0, $deep=0) { $db = $this; static $path; echo "<ul"; if($deep!=0) echo " class='child'"; echo ">"; #--> Startwerte errechnen if($firstcall) { echo "<li class='border_bottom'"; if($this->cid==0) echo " id='selected'"; echo "><a href='?id=12'>Home</a></li>"; if(!$this->cid) $id = 12; else $id = $this->cid; do { $result = $db->mysqlArray("select cid, parent from content where cid='".$id."'"); $path[] = $result[2][0]['cid']; $id = $result[2][0]['parent']; } while($result[2][0]['parent']!=0); } #--> Einzelne Ebene auslesen $next_deep = $db->mysqlQuery("select cid, nav_title from content where parent='".$db->sqlij($parent)."' order by corder"); $i=0; while ($zeile=mysql_fetch_assoc($next_deep)) { echo "<li"; if($this->cid==$zeile['cid']) echo " id='selected'"; if($i<mysql_num_rows($next_deep)-1 || $deep!=0) echo " class='border_bottom'"; echo ">"; echo "<a href='?id=".$zeile['cid']."'>".stripslashes($zeile['nav_title'])."</a>"; echo "</li>n"; #--> Rekursiven aufruf ausfuehren $parents = $db->mysqlQuery("select cid from content where parent='".$db->sqlij($zeile['cid'])."'"); if(mysql_num_rows($parents)>0 && count($path)>=($deep+1) && $path[(count($path)-$deep-1)]==$zeile['cid']) { echo "<li class='parent'>"; $this->getTreemenu(false, $zeile['cid'], $deep+1); echo "</li>"; } } $i++; echo "</ul>"; } } /*** * Init */ $object = new treeMenu($_GET['id']); $object->mysqlConnect($sql['host'], $sql['user'], $sql['pass'], $sql['data'], 'utf8'); <html> <head> <title>Treemenu Beispiel</title> <style type="text/css"> div.boxcontent_left { width:500px; } div.boxcontent_left ul { margin:5px 0px 0px 0px; } div.boxcontent_left ul.child { padding:0px 0px 0px 0px; margin:0px 0px 0px 0px; } div.boxcontent_left li { list-style-type:none; background-image:none; padding:2px 0px 2px 5px; margin:0px 0px 0px 0px; vertical-align:middle; background-position:3px -1px; } div.boxcontent_left li.parent { padding-left:15px; } div.boxcontent_left li:hover { background-color:#c0c0c0; } div.boxcontent_left li.parent:hover { background-color:transparent; } div.boxcontent_left li.border_top { border-top:1px solid #a0a0a0; } div.boxcontent_left li.border_bottom { border-bottom:1px solid #a0a0a0; } div.boxcontent_left li a { border:0px; display:block; width:auto; } div.boxcontent_left li a:link { color:black; text-decoration:none; } div.boxcontent_left li a:active { color:black; text-decoration:none; } div.boxcontent_left li a:visited { color:black; text-decoration:none; } div.boxcontent_left li a:hover { color:black; text-decoration:none; font-weight:bold; } div.boxcontent_left li#selected { font-weight:bold; } </style> </head> <body> <div class="boxcontent_left"> $object->getTreemenu(true); </div> </body> </html> |
Die Klasse enthält einige Methoden, die sich nur um die Datenbankverbindung kümmern. Die werde ich jetzt nicht weiter beschreiben.
Die Methode getTreemenu(true) ist das Herzstück des Ganzen. Diese generiert rekursiv das Baummenü. Beim Aufruf dieser Methode muss ein "true" übergeben werden, um den Erstaufruf anzuzeigen. Bei diesem Erstaufruf wird der Pfad zum Zielast definiert.
Wenn man zum Beispiel zu dem Eintrag "Ebene 3" anzeigen möchte, sieht der Pfad wie folgt aus:
array(3) { [0]=> 4, [1]=> 2, [2]=> 1 }
Dieses Array wird gespiegelt (also rekursiv) verwendet, um den richtigen Baum zu öffnen.
Nun wird einfach nach der ID gesucht, die sich in der ersten Ebene befindet. Also die ID 1. Ist diese erreicht, ruft sich die Methode selber wieder auf. Diesmal wird der Methode ein "false" übergeben, da der Pfad ja schon ermittelt wurde. Jetzt wird nach der ID 2 gesucht. Und der ganze Spaß beginnt von vorne.
Schlusswort
Um das Beispiel ausführen zu können, muss die MySQL Tabelle in einer Datenbank angelegt werden. Danach muss man nur noch die Zugangsdaten in die vier Variablen eingetragen werden.




