
Zitat von
theo
Glückwunsch!
Heute Abend werde ich Dein Script mal testen. Wenn es wirklich läuft, dann wäre das ein wirklich schöner Erfolg für diesen Workshop.
Hardy
Hey Theo, ich hoffe du kamst schon zum Testen, denn es funktioniert bei mir immernoch tadellos!
Ich hab auch noch eine wichtige Erweiterung gebastelt: Wurzeln verschieben
Zudem hab ich den Adminbereich an die Baumstruktur angepasst, wie man hier sieht:
Die ganzen Buttons häufen sich zwar, dafür hat man IMHO eine bessere Übersicht und erkennt sofort was passiert.
Nun aber zu den Änderungen:
1. Es muss eine neue Spalte in der Datenbank - am Ende der Tabelle node - angelegt werden.
Die Spalte heißt in meinem Beispiel einfach root_seq (abgeleitet von sequence und bedeutet soviel, dass dort die Reihenfolge der Knoten gespeichert wird).
Eigentlich geschiet dies ja schon in der root_id. Doch hatte ich Probleme als ich mit dieser arbeitete, also hab ich ne zusätzliche Spalte eingefügt.
Der Sinn liegt einfach darin, dass hier eine lückenlose Aufreihung der Wurzeln inkl. Blättern usw. erfolgt.
Praktisches Beispiel:
Wir nehmen eine Tabelle an wie wir sie kennen (lft und rgt lass ich der übersicht halber einfach mal weg)
Code:
root_id payload
1 root1
2 root2
3 root3
4 root4
5 root5
Löscht man hier z.B. root3 entsteht eine Lücke bei den root_id's.
Code:
root_id payload
1 root1
2 root2
4 root4
5 root5
Hier kommt die root_seq ins Spiel. Die Tabelle vor dem Löschen von root3
Code:
root_id payload root_seq
1 root1 1
2 root2 2
3 root3 3
4 root4 4
5 root5 5
Und jetzt nach dem Löschen von root3
Code:
root_id payload root_seq
1 root1 1
2 root2 2
4 root4 3
5 root5 4
Die Anpassung der root_seq's ab root4 erfolgt natürlich irgendwo im Skript (das zeig ich dir/euch auch gleich).
Dank dieser lückenlosen Abfolge kann man dann relativ einfach eine Wurzel verschieben, indem man deren root_seq einfach mit dem nachfolger bzw. vorgänger tauscht.
Mir kam (auch) der Gedanke, dass die Spalte überflüssig ist und dass man es auch mit der root_id lösen könnte. Wie gesagt scheiterte ich daran, denn die Blätter der Wurzeln wurden bei mir auf diesem Wege immer zu Waisen.
Nu gehts aber los!
Hier suchen wir uns die größte ODER die kleinste root_seq raus.
Wozu das ganze? Das sag ich euch gleich. ;-)
PHP-Code:
/** min und max root_seq - dient später zum benutzen der verschiebefunktion von roots **/
function getRootExtremes($welches) {
if ($welches == 'min'):
$sql = "SELECT min(root_seq) AS min FROM node";
$result = mysql_query($sql, connectDB());
$row = mysql_fetch_array($result);
return $row['min'];
else:
$sql = "SELECT max(root_seq) AS max FROM node";
$result = mysql_query($sql, connectDB());
$row = mysql_fetch_array($result);
return $row['max'];
endif;
}
Wozu diese Funktion? Ganz einfach, im Adminbereich soll ein Hochschieben von Wurzeln doch nur möglich sein, wenn die Wurzel nicht eh schon ganz oben steht. Dasselbe gilt fürs Abwärtsschieben.
Im folgenden müßt ihr den 1. Zweig von showNavi()
also alles zwischen
PHP-Code:
if ($_REQUEST['site'] == "admin"):
und
gegen das hier austauschen:
PHP-Code:
$level = 1;
$tree.= '<ul id="NewTree">';
while($row = mysql_fetch_array($result)) {
if ($row['level'] > $level) // wenn neuer level
$tree.= '<ul>';
else if ($row['level'] < $level)
$tree.= str_repeat('</li></ul>', $level-$row['level']);
else if ($level > 1)
$tree.= '</li>';
$tree.= '<li value_id="'.$row['node_id'].'" level="'.$row['level'].'" input_id="'.$row['root_id'].'" productgroupname="" input_type="">';
$tree.= '<span>'.$row['payload']; // name
// die nächsten beiden ifs werden leider nicht für roots berücksichtigt
// hochrutschen nur wenn vorgänger vorhanden
if (($row['upper'] == 1)):
$tree.= ' <a href="'.$PHP_SELF.'?site=admin&action=moveup&id='.$row[0].'"><img src="img/up.png" border="0"></a> '; // hochschieben
endif;
// runterrutschen nur wenn nachfolger vorhanden
if ($row['lower'] == 1):
$tree.= ' <a href="'.$PHP_SELF.'?site=admin&action=movedown&id='.$row[0].'"><img src="img/down.png" border="0"></a> '; // hochschieben
endif;
// root-verschiebebuttons
// die nächsten beiden ifs werden NUR für roots berücksichtigt
// hochrutschen nur wenn es ein root ist (also lft = 1) und größer als minimalwert
if (($row['root_seq'] > getRootExtremes('min')) && ($row['lft'] == 1)):
$tree.= ' <a href="'.$PHP_SELF.'?site=admin&action=rootmoveup&id='.$row[0].'"><img src="img/up.png" border="0"></a> '; // hochschieben
endif;
// runterrutschen nur wenn es ein root ist (also lft = 1) und kleiner als der maximalwert
if (($row['root_seq'] < getRootExtremes('max')) && ($row['lft'] == 1)):
$tree.= ' <a href="'.$PHP_SELF.'?site=admin&action=rootmovedown&id='.$row[0].'"><img src="img/down.png" border="0"></a> '; // hochschieben
endif;
$tree.= '<a href="'.$PHP_SELF.'?site=admin&action=edit&id='.$row[0].'"><img src="img/edit.png" border="0"></a> '; // umbenennen
$tree.= '<a href="'.$PHP_SELF.'?site=admin&action=insert&id='.$row[0].'"><img src="img/insert.png" border="0"></a> '; // unterhalb einfügen
$tree.= '<a href="'.$PHP_SELF.'?site=admin&action=del&id='.$row[0].'"><img src="img/del.png" border="0"></a></span>'; // löschen
$level = $row['level'];
} // while
$tree.= str_repeat('</ul>', $level-1);
Ihr seht schon: Auch die Einträge, die keine Wurzel sind (also alles innerhalb einer Wurzel), bekommen den hoch- und runterschiebebutten nur, wenn sie nicht erstes bzw. letztes Element im Teilbaum sind. Guckt euch dazu am besten einfach nochmal die obere Grafik (in diesem Posting) an.
Im in der getNavi() müßt ihr nur die Zeile (kommt 2x vor)
PHP-Code:
ORDER BY n.root_id,n.lft";
mit root_seq erweitern, also so
PHP-Code:
ORDER BY n.root_seq,n.root_id,n.lft";
Doch damit das alles funktioniert, fehlt noch was: rootMove() ;-)
Ich geh dabei nach folgendem, typischen Tauschschema vor:
Beispiel:
Code:
a = 1
b = 2
c = 3
nun möchte ich b und c tauschen:
b = 0 // da 0 ja eh nie auftaucht, ist das hier ne temporäre zuweisung
c = 2
b = 3
Ich bin mir nicht sicher, obs in sql geschicktere Lösungen gibt. Da wärs nett, wenn mich jemand verbessert.
PHP-Code:
/** wurzeln verschieben **/
function rootMove($id,$direction) {
$node = getNode($id);
if ($direction == "down"):
// erstmal die auszutauschenden werte auf 0 setzen
$sql = "UPDATE node
SET root_seq = 0
WHERE root_seq = ".$node[5];
$result = mysql_query($sql, connectDB());
// root_seq anpassen - sprich die nachfolger um 1 vermindern
$sql = "UPDATE node
SET root_seq = root_seq - 1
WHERE root_seq = ".$node[5]." + 1";
$result = mysql_query($sql, connectDB());
// die soeben genullten werte auf das ursprüngliche + 1 erhöhen
$sql = "UPDATE node
SET root_seq = ".$node[5]." + 1
WHERE root_seq = 0";
$result = mysql_query($sql, connectDB());
else:
// erstmal die auszutauschenden werte auf 0 setzen
$sql = "UPDATE node
SET root_seq = 0
WHERE root_seq = ".$node[5];
$result = mysql_query($sql, connectDB());
// root_seq anpassen - sprich die vorgänger um 1 erhöhen
$sql = "UPDATE node
SET root_seq = root_seq + 1
WHERE root_seq = ".$node[5]." - 1";
$result = mysql_query($sql, connectDB());
// die soeben genullten werte auf das ursprüngliche um 1 vermindern
$sql = "UPDATE node
SET root_seq = ".$node[5]." - 1
WHERE root_seq = 0";
$result = mysql_query($sql, connectDB());
endif;
}
Nun sind die root_seq-Werte vertauscht. Entweder getauscht mit dem Vorgänger oder mit dem Nachfolger, je nachdem welchen Pfeil man klickt.
Doch damit das ganze aufgerufen wird, brauchen wir noch einen Zusatz in der index.php
Dort fügt ihr das
PHP-Code:
case "rootmoveup":
$error = rootMove($_REQUEST['id'],"up");
break;
case "rootmovedown":
$error = rootMove($_REQUEST['id'],"down");
break;
direkt unter der Zeile
PHP-Code:
switch($_REQUEST['action']){
oder wo auch immer (hauptsache anständig im switch-konstrukt) ein.
Jetzt sind wir auch schon fast fertig. 2 Schritte fehlen noch auf dem Weg zur Wurzelbehandlung *ha der war gut*
Zunächst gehts noch ums Löschen der Wurzeln. Wenn eine Wurzel gelöscht wird, müssen die Werte für root_seq der nachfolgenden Wurzeln um 1 vermindert werden, um die Lücke zu schließen.
Dazu fügt ihr in der Funktion nodeDel()
einfach das hier ein:
PHP-Code:
$sql = "UPDATE node
SET root_seq = root_seq - 1
WHERE root_seq > ".$node[5];
$result = mysql_query($sql, connectDB());
Nun gehts an die letzte Funktion nodeIns():
Um beim Einfügen der Knoten auch brav die zugehörige root_seq einzufügen, muss beim INSERT auch root_seq angegeben werden. Also aus
PHP-Code:
$sql = "INSERT INTO node (root_id,payload,lft,rgt)
VALUES (".$node[1].",'".$name."',".$node[3].",".($node[3]+2).")";
wird
PHP-Code:
$sql = "INSERT INTO node (root_id,payload,lft,rgt,root_seq)
VALUES (".$node[1].",'".$name."',".$node[3].",".($node[3]+2).",".$node[5].")";
Tauscht das eben genannte bitte nicht einfach blind aus. Erweitert die letzte Spalte lieber, um auf Nr. sicher zu gehen. Denn es handelt sich um 2 unterschiedliche Statements, die erweitert werden müssen.
Ich hab bei mir der Übersicht halber mysql_fetch_array, statt mysql_fetch_row benutzt. Angeblich ist es verschwindend langsamer, man kann jedoch mehr mit dem fremden Code anfangen, als mit bloßen Zahlen (ich zumindest).
Doch keine Sorge, hier im Posting bleibt alles bei Zahlen - ihr brauch kein row gegen array tauschen. 
Den letzten else-zweig dieser Funktion (nodeIns) könnt ihr nun doch noch getrost gegen diesen Inhalt austauschen:
PHP-Code:
$sql = "SELECT max(root_id) as maxroot, max(root_seq) as maxrootseq
FROM node";
$result = mysql_query($sql, connectDB());
$row = mysql_fetch_row($result);
$root_id = $row[0];
$root_seq = $row[1];
$sql = "INSERT INTO node (root_id,payload,lft,rgt,root_seq)
VALUES (".($root_id+1).",'".$name."',1,2,".($root_seq+1).")";
$result = mysql_query($sql, connectDB());
Das muss es gewesen sein. :-)
Hoffentlich hab ich dem Tutorial, welches mir bis jetzt enorm geholfen hat, auch ein wenig geholfen.