PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Nested Set nur Level weise ausgeben


jasonpetra
26.12.2007, 16:33:48
Hi,

habe meine Kategorieverwaltung mit nested set aufgebaut.
Meine mysql tabelle sieht wie folgt aus :

node_id
root_id
payload
lft
rgt

Mit function gebe ich die Tabelle aus:

Erste function : navigation aufbauen


/** navigation aufbauen **/
function getNavi() {
$sql = "SELECT DISTINCT root_id AS roots
FROM node";

$result = mysql_query($sql, connectDB());
$count = mysql_num_rows($result);

while($row = mysql_fetch_array($result)){
$root[] = $row[0];
} // while

$sql= "SELECT n.*,
floor((n.rgt-n.lft-1)/2) AS childs,
count(*)+(n.lft>1) AS level,
((min(p.rgt)-n.rgt-(n.lft>1))/2) > 0 AS lower,
(((n.lft-max(p.lft)>1))) AS upper
FROM node n, node p ";
if ($count > 1) { // fuer mehrere wurzeln
$sql.= "WHERE n.lft BETWEEN p.lft AND p.rgt
AND (p.root_id = n.root_id)
AND (p.node_id != n.node_id OR n.lft = 1)
AND (p.root_id IN (".implode(",",$root)."))
GROUP BY n.root_id,n.node_id
ORDER BY n.root_id,n.lft";
} elseif ($count == 1) { // ... oder eben nur eine
$sql.= "WHERE n.lft BETWEEN p.lft AND p.rgt
AND (p.root_id = n.root_id)
AND (p.node_id != n.node_id OR n.lft = 1)
AND (p.root_id = ".$root[0].")
GROUP BY n.node_id
ORDER BY n.lft";
} else { // alle wurzeln ... der defaulf-fall eben
$sql.= "WHERE n.lft BETWEEN p.lft AND p.rgt
AND (p.root_id = n.root_id)
AND (p.node_id != n.node_id OR n.lft = 1)
GROUP BY n.root_id,n.node_id
ORDER BY n.root_id,n.lft";
}


$result = mysql_query($sql, connectDB());

return $result;
}



Die zweite function:


/** navigation ausgeben **/
function showNavi() {
$result = getNavi();

// diese funktion ist dermassen unsauber *ganzrotwerd*
// die muss unbedingt noch ueberarbeitet werden!
if ($_REQUEST['site'] == "admin"):
$tree = "<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\"><form action=\"\" method=\"post\">";
$tree.= "<tr id=\"top\"><th>Wurzel</th>";
$tree.= "<th>Name</th><th>Ebene</th>";
$tree.= "<th>Verschieben</th><th>Löschen</th>";
$tree.= "<th>Einfügen</th>";
$tree.= "<th>Editieren</th></tr>";
while($row = mysql_fetch_array($result)) {
($race/2 == floor($race/2)) ? $class = "line1" : $class = "line2";
$tree.= "<tr><td align=\"center\" class=\"".$class."\">".$row[1]."</td>";
$tree.= "<td class=\"".$class."\">".$row[2]."</td>";
$tree.= "<td align=\"center\" class=\"".$class."\">".$row[6]."</td>";
$tree.= "<td align=\"center\" class=\"".$class."\"><a href=\"".$PHP_SELF."?site=admin&action=moveup&id=".$row[0]."\" onfocus=\"blur()\"><img src=\"img/up.png\" border=\"0\"></a> ";
$tree.= "<!-- <a href=\"".$PHP_SELF."?site=admin&action=movedown&id=".$row[0]."\" onfocus=\"blur()\"><img src=\"img/down.png\" border=\"0\"></a> --></td>";
$tree.= "<td align=\"center\" class=\"".$class."\"><a href=\"".$PHP_SELF."?site=admin&action=del&id=".$row[0]."\" onfocus=\"blur()\"><img src=\"img/del.png\" border=\"0\"></a></td>";
$tree.= "<td align=\"center\" class=\"".$class."\"><a href=\"".$PHP_SELF."?site=admin&action=insert&id=".$row[0]."\" onfocus=\"blur()\"><img src=\"img/insert.png\" border=\"0\"></a></td>";
$tree.= "<td align=\"center\" class=\"".$class."\"><a href=\"".$PHP_SELF."?site=admin&action=edit&id=".$row[0]."\" onfocus=\"blur()\"><img src=\"img/edit.png\" border=\"0\"></a></td></tr>";
$race+=1;
} // while
$tree.= "</form></table>";
else:
// bei diesem teil darf ich mich fuer die hilfe von jan bedanken
$level = 1;
$tree.= "<ul id=\"NewTree\">";

while($row = mysql_fetch_array($result)) {
if ($row['level'] > $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=\"\"><span>".$row[2]."</span>";
$level = $row['level'];
} // while
$tree.= str_repeat("</ul>", $level-1);
endif;

return $tree;
}


So, nun mein problem:

Diese functionen geben den ganzen Baum, mit Wurzeln usw..., aus.
Ich möchte es aber Levelweise ausgeben, das heißt,
Nur die Wurzeln als Link, wenn ich z.B. auf Wurzel1 klicke,
soll nur der Level 2 der Wurzel1 als Link ausgeben werden,
wenn bei Level 2 klicke, nur der Level 3, usw..

Kann mir da jemand weiterhelfen, sitze schon zwei Tage an den functionen.

Dank im voraus

Chris

defabricator
26.12.2007, 17:51:14
http://dev.mysql.com/tech-resources/articles/hierarchical-data.html
Steht im Paragraphen "Find the Immediate Subordinates of a Node"

Wenn Du eine allgemeine Codebasis zu einem Problem suchst (hier nested sets), dann schau doch immer mal bei PEAR vorbei. http://pear.php.net/package/DB_NestedSet2
http://pear.php.net/manual/en/installation.php

jasonpetra
26.12.2007, 18:53:42
Danke erst mal, hat mir schon sehr geholfen.

Bin jetzt soweit, daß ich den ansatz für eine sql abfrage habe, und zwar:


SELECT node.payload, (COUNT(parent.payload) - (sub_tree.depth + 1)) AS depth
FROM node AS node,
node AS parent,
node AS sub_parent,
(
SELECT node.payload, (COUNT(parent.payload) - 1) AS depth
FROM node AS node,
node AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND node.payload = 'Sony'
GROUP BY node.payload
ORDER BY node.lft
)AS sub_tree
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND node.lft BETWEEN sub_parent.lft AND sub_parent.rgt
AND sub_parent.payload = sub_tree.payload
GROUP BY node.payload
HAVING depth >= 1
ORDER BY node.lft;


Nun hab ich noch das problem, daß ich ja mehrere Wurzel habe, daß
heißt, ich muß noch irgendwo einfügen, von welcher Wurzel (ID der Wurzel)
er es anzeigen soll?

Oder lieg ich da jetzt total falsch???
Hilfe

defabricator
26.12.2007, 18:57:34
Das kannst Du doch in der Abfrage bereits angeben.

jasonpetra
26.12.2007, 19:00:54
Hab ich gerade probiert, bekomms aber nicht hin:


SELECT node.payload, (COUNT(parent.payload) - (sub_tree.depth + 1)) AS depth
FROM node AS node,
node AS parent,
node AS sub_parent,
(
SELECT node.payload, (COUNT(parent.payload) - 1) AS depth
FROM node AS node,
node AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND node.node_id= '4'
GROUP BY node.payload
ORDER BY node.lft
)AS sub_tree
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND node.lft BETWEEN sub_parent.lft AND sub_parent.rgt
AND sub_parent.payload = sub_tree.payload
GROUP BY node.payload
HAVING depth = 1
ORDER BY node.lft;




Er zeigt mir immer alle Wurzel an.

Habs gerade probiert, wenn ich nur eine Wurzel habe, funktioniert es.
Mit mehreren nicht.

defabricator
26.12.2007, 19:32:35
Dann fasst die verschiedenen (Sub-)Wurzeln halt unter einer echten Wurzel zusammen.

jasonpetra
26.12.2007, 19:36:40
Hab ich mir auch gerade gedacht.

jasonpetra
27.12.2007, 10:56:19
Letzte Frage,

muß in dieser Abfrage noch die jeweiligen node_id's mit
auslesen, weiß aber nicht wo?


SELECT node.payload, (COUNT(parent.payload) - (sub_tree.depth + 1)) AS depth
FROM node AS node,
node AS parent,
node AS sub_parent,
(
SELECT node.payload, (COUNT(parent.payload) - 1) AS depth
FROM node AS node,
node AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND node.node_id= '4'
GROUP BY node.payload
ORDER BY node.lft
)AS sub_tree
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND node.lft BETWEEN sub_parent.lft AND sub_parent.rgt
AND sub_parent.payload = sub_tree.payload
GROUP BY node.payload
HAVING depth = 1
ORDER BY node.lft;


Dann kann ich den link der Abfrage mit der node_id
versehen.

defabricator
27.12.2007, 11:13:39
Ich tippe mal auf
SELECT node.node_id, node.payload, (COUNT(parent.payload) - (sub_tree.depth + 1)) AS depth
FROM node AS node,
node AS parent,
node AS sub_parent,
...

jasonpetra
27.12.2007, 12:12:55
Hab ich gemacht, funktioniert super, danke.