Hallo zusammen
Vorneweg: Dieses Tutorial ist für Personen gedacht, welche schon Erfahrungen mit PHP gesammelt haben, und für die MySQL keine Unbekannte mehr ist. Es wird zum Teil relativ komplex, was auch mit besten Erklärungen von meiner Seite auch noch recht schwierig sein könnte.
In meinem Tutorial geht es darum, eine komplett dynamische Navigation zu erstellen, ohne Hintergründe über Daten bzw. Files des Servers preiszugeben. Alles wird über die index.php aufgerufen, und anhand von index.php?nav_id=xx weitergeleitet.
Eine mögliche Designvariante ist im Bild angehängt (nur kurz strukturiert).
Um die Idee in der DB zu sehen, hier der MySQL-Code:
Code :
1
2
3
4
5
6
7
8
9
10
| CREATE TABLE `menu` (
`menu_ID` int(11) NOT NULL auto_increment,
`menu_topid` int(11) NOT NULL default '0',
`menu_position` int(11) NOT NULL default '0',
`menu_name` text collate utf8_unicode_ci NOT NULL,
`menu_page` int(11) NOT NULL default '0',
PRIMARY KEY (`menu_ID`),
KEY `menu_topid` (`menu_topid`),
KEY `menu_page` (`menu_page`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=0; |
Kleiner Beschrieb zur Tabelle, was die dazugehörigen Felder bedeuten:- menu_ID ist die ID jedes einzelnen Menus
- menu_topid ist die ReferenzID, d.H. wenn der neue Menu-Eintrag unter einem anderen Menu auftauchen will. Theoretisch ist dies unendlich verschachtelbar, irgendwo macht wird es dann aber mit dem Design schwierig und der Übersichtlichkeit der Menüs.
- menu_position regelt die Position von den Elementen, welches die gleiche menu_topid haben. Je kleiner die Zahl, desto weiter vorn im Array, danach sortiert nach menu_ID.
- menu_name Der Name des Menu's welcher auch angezeigt werden will
- menu_page Auf welchen Seiteninhalt (content_ID) sich der Menueintrag beruft, welcher in der unteren Tabelle beschrieben wird.
Um die Inhalte auch dynamisch einfach zu halten, legen wir die auch gleich in die Datenbank ab. Diese Daten werden anschliessend direkt auf der Seite je nach gewähltem Menü ausgegeben:
Code :
1
2
3
4
5
6
| CREATE TABLE `content` (
`content_ID` int(10) NOT NULL auto_increment,
`content_title` varchar(45) collate utf8_unicode_ci NOT NULL default '',
`content_text` text collate utf8_unicode_ci NOT NULL,
PRIMARY KEY (`content_ID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=4 ; |
- content_ID Die ID jedes Eintrages
- content_title Der Titel des Eintrages, wird in meinem Tutorial hier seperat gehalten, um für euch später einfacher dies in den Header zu setzen
- content_text Der Inhalt. Je nach Erweiterung von euch entweder schon in reinem HTML, oder in einem PseudoCode (ala BB-Code oder vB Code)
In einer ersten Phase will ich die Menu auslesen, welches eine menu_topid von 0 haben, also immer angezeigt werden.
PHP-Code:
$mysql->query("SELECT menu_ID, menu_name FROM menu WHERE menu_topid=0 and `menu_display` != '0' ORDER BY menu_position ASC");
$nav_array = array();
$i = 0;
while ($nav_data = $mysql->fetcharray()) {
$nav_array[$i] = array('menu_ID'=>$nav_data["menu_ID"], 'menu_name'=>$nav_data["menu_name"]);
$i++;
}
Jetzt habt ihr ein Array mit allen Inhalten für die Topnavigation. Diese müsst ihr je nach Templatesystem entweder noch aufbereiten, oder könnte es so an z.B. Smarty weitergeben.
Anschliessend muss geschaut werden, welche nav_id von der URL übergeben wurde.
Falls die ID kleiner oder gleich 0 ist, wird die ID des ersten Eintrages des oberen Arrays genommen, was in unserem Fall immer die Startseite ist.
PHP-Code:
$nav_id = (int) $_GET["nav_id"];
if ($nav_id <= 0) {
$nav_id = $nav_array[0]['menu_ID'];
}
Anschliessend lesen wir alle Informationen des Menus aus. Ide $page_id ist hier die ID von der Tablle content.
PHP-Code:
$mysql->query("SELECT * FROM menu WHERE menu_ID = $nav_id");
$page_data = $mysql->fetcharray();
$page_id = $page_data["menu_page"];
Bis jetzt haben wir nur an der Oberfläche gekratzt. Wir kennen bis jetzt nur die Top-Navigation, und welche Seite eigentlich ausgegeben werden soll.
Was wir noch nicht wissen, in welcher Unternavigation wir uns befinden, und wie weit es geht, bis wir eine topid finden, die 0 ist. Um es zu erklären versuche ich es ein bischen "zeichnerisch" zu erklären. Nehmen wir an, die nav_id ist 3, dann ist unsere menu_ID = 3. Der einfachheit halber hab ich das menu_ hier weggelassen...
topid =0, ID = 1topid = 1, ID = 2
topid = 2, ID = 3
topid = 3, ID = 4
Das einzige was wir wissen, ist das unsere ID 3 ist, und die topid =2 ist. Wir wissen aber nicht, wieviele Parrents (Eltern) noch unter uns sind, ob wir gleich unter der topnav sind (topid == 0) oder ob wir noch x Stufen vor uns haben. Ebenso wissen wir nicht, ob wir noch Childs (Kinder) haben, die eine Stufe höher liegen.
Um das Menu nicht unnötig aufzublähen wird in meinem Beispiel auch nur die direkten Childs-Stufe (eigene Kinder) gezeigt, und nicht auch noch deren Nachfahren. Aber damit das Menu überhaut logisch dargestellt wird, muss ich all meine Vorfahren kennen.
1. Schritt:
Ich muss zuerst all meine Kinder kennen. Denn sonst kann ich das Menu am Schluss nicht sauber darstellen. Menus werden von innen nach aussen gebildet, damit die Reihenfolge simmt.
Dazu mach ich zuerst 2 Arrays. Zugleich setze ich die Variable $invlevel = 1.
1 ist in meinem Fall die innerste Stufe, die Stufe des Childs.
PHP-Code:
$child_array = array();
$root_array = array();
//Die Stufe beginnt von unten zu zählen, statt von oben. Wird am Schluss umgerechnet
$invlevel = 1;
Jetzt werden die "Kinder" ausgelesen, und ins array $child_array abgelegt.
PHP-Code:
$mysql->query("SELECT menu_ID, menu_topid, menu_name FROM menu WHERE menu_topid = $nav_id and `menu_display` != '0' ORDER BY menu_position");
$i = 0;
while ($subnav_data = $mysql->fetcharray()) {
$child_array[$i] = array('menu_ID'=>$subnav_data["menu_ID"], 'menu_name'=>$subnav_data["menu_name"], 'menu_topid'=>$subnav_data["menu_topid"], 'level'=>$invlevel);
$i++;
}
Könnte ja sein, dass meine ID selber die topid = 0 hat, d.H. ich könnt hier mit dem Prüfen meiner "Eltern" gleich aufhören. Sonst muss nach den Eltern geprüft werden:
PHP-Code:
//Die nächsthöhere TopID
$next_topid = $page_data["menu_topid"];
//Solange durchlaufen lassen bis obersten Navitationsteile erreicht sind (top_id == 0)
while (($next_topid != 0 || $next_topid != false)) {
$top_id kann aus dem Array $child_array herausgelesen werden
beim 1. Durchgang kann das Child-Array leer sein, man kann dafür die $nav_id nehmen
PHP-Code:
if(empty($child_array[0]["menu_topid"])) {
$top_id = $nav_id;
} else {
$top_id = $child_array[0]["menu_topid"];
}
Erhöhung des $invlevels, da eine Stufe weiter Richtung oben, und erstellen des Querys für die Eltern.
Danach wird das Array ausgelesen und ins root_array abgelegt.
PHP-Code:
$invlevel++;
$i = 0; //Zähler in der Schlaufe
$mysql->query("SELECT menu_ID, menu_topid, menu_name FROM menu WHERE menu_topid = $next_topid ORDER BY menu_position ASC");
//Die Tabelle auslesen
while($subnav_data = $mysql->fetcharray()) {
$root_array[$i] = array('menu_ID'=>$subnav_data["menu_ID"], 'menu_name'=>$subnav_data["menu_name"], 'menu_topid'=>$subnav_data["menu_topid"], 'level'=>$invlevel);
Um nicht irgendwann unsere Childs am Schluss der Navigation zu haben, wird auch geprüft, ob die topid der Menu_ID entspricht. Falls dies der Fall sein sollte, wir das Array mit der Funktion array_merge zusammengefügt.
PHP-Code:
if($root_array[$i]["menu_ID"] == $top_id) {
$root_array = array_merge($root_array, $child_array);
//Minus 1, weil es sonst einen Zwischenraum gibt. Z.B. $root_array[2], dann $root_array[4]
$i = count($root_array) - 1;
}
$i++;
}
So, die mittlere Schlaufe ist geschlossen. Wir kennen jetzt unsere direkten Eltern, jetzt get es genau gleich weiter bis wir wissen, von wo wir genau abstammen.
Dazu wird das $child_array = $root_array, und selbiges wird wieder geleert.
PHP-Code:
$child_array = $root_array;
$root_array = array();
Jetzt muss die nächste topid herausgefunden werden, nach der wir nun den ganzen Durchlauf machen können.
PHP-Code:
//Hier wird noch mit der alten $next_topid gerechnet. Die Topid vom höheren Menu wird gelesen
$mysql->query("SELECT menu_topid FROM menu WHERE menu_ID = $next_topid LIMIT 1");
$subnav_data = $mysql->fetcharray();
//Neues $next_topid
$next_topid = $subnav_data["menu_topid"];
}
Am Ende dieses Marathons haben wir nun alle Daten des Untermenüs oder auch subnav genannt.
Aber die Daten sind noch in einer falschen Reihenfolge. Die oberste (älteste) Stufe, hat die höchste levelid. Wer aufmerksam mitverfolgt hat, hat gemerkt dass wir diese Daten auch immer ins Array geschrieben wurde. Dazu wird jetzt das ganze mehr oder weniger selbsterklärend umgekehrt.
PHP-Code:
$anzlevel = $invlevel;
$invlevel = 0;
$number = count($child_array);
//Die Umrechnunsschleife, die Levels werden neu gesetzt: Das Höchste jetzt das Tiefste und umgekehrt
for($i = 0; $i < $number; $i++) {
$invlevel = $child_array[$i]['level'];
$child_array[$i]['level'] = $anzlevel - $invlevel + 1;
}
//Die Subnav_array mit dem vollständigen child_array füllen
$subnav_array = $child_array;
Das Menu haben wir nun komplett... Aber der Inhalt fehlt noch. Dies ist aber zum Glück keine weiter schwierige Sache:
PHP-Code:
$mysql->query("SELECT * FROM content WHERE content_ID = $page_id");
$data = $mysql->fetcharray();
$content_title = $data["content_title"];
$content_text = $data["content_text"];
if ($content_title == "" && $content_text == "") {
$content_title = "JClub-Noch kein Inhalt";
$content_text = "Keine Daten gefunden";
}
Die Daten sind jetzt Ausgabe-fertig.
Wissenswertes zum Schluss:- Die ganzen MySQL-Aufrufe gehen über eine eigene Klasse (in PHP5).
- Der ganze Code steht unter GPL, ich habe die Aufbereitung der Daten in Smarty gemacht.
- Ideen dazu, wie man so was machen könnte, bzw. wo ihr meine Arbeit findet, steht in meiner Signatur.
Lesezeichen