I am trying to create a way to retrieve and display an endless amount of nested categories.
Now I could select them like this (not tested, not important):
$resulttable1 = mysql_query("SELECT name, id FROM categories WHERE childof=0");
while($rowtable1 = mysql_fetch_array($resulttable1)){
$cat1 = $rowtable['name'];
$resulttable2 = mysql_query("SELECT name, id FROM categories WHERE childof=$rowtable1[id]");
while($rowtable2 = mysql_fetch_array($resulttable2)){
$cat2 = $rowtable2['name'];
$resulttable3 = mysql_query("SELECT name, id FROM categories WHERE childof=$rowtable2[id]");
while($rowtable3 = mysql_fetch_array($resulttable3)){
$cat3 = $rowtable3['name'];
}
}
}
But what if a user wants more than 3 "levels" of nesting? How can I make the mysql SELECT in a way that it retrieves an endless amount of nested categories?
UPDATE: Ok, using the link paul provided I got it done like this:
It's not really important how the lft and rgt fields work as they get updated automatically when you insert and remove categories. It's interesting to find out, though. Also, the first entry is a static value. It's basically just the start of the tree, just leave it in as-is. My script below doesn't echo it based on it's title "products".
<?php
include_once("config.php");
display_tree('products');
function display_tree($root) {
echo'<table>';
// retrieve the left and right value of the $root node
$result = mysql_query('SELECT lft, rgt FROM tree '.
'WHERE title="'.$root.'";');
$row = mysql_fetch_array($result);
// start with an empty $right stack
$right = array();
// now, retrieve all descendants of the $root node
$result = mysql_query('SELECT title, lft, rgt FROM tree '.
'WHERE lft BETWEEN '.$row['lft'].' AND '.
$row['rgt'].' ORDER BY lft ASC;');
// display each row
while ($row = mysql_fetch_array($result)) {
// only check stack if there is one
if (count($right)>0) {
// check if we should remove a node from the stack
while ($right[count($right)-1]<$row['rgt']) {
array_pop($right);
}
}
// display indented node title
$repeatamount = (count($right)) - 1;
if($repeatamount < 0){ $repeatamount = 0; }
if($row['title'] != 'products'){
echo'<tr>';
echo "<td>".str_repeat('-->',$repeatamount ).$row['title']."</td>";
echo'</tr>';
}
// add this node to the stack
$right[] = $row['rgt'];
}
echo'</table>';
}
?>
Which will display something like:
And this is an example for inserting a new category: addnew.php?parent=3&title=Shooter which would add the category "Shooter" under "PC" (which is in turn under "Games").
<?php
include_once("config.php");
if(isset($_GET['parent']) && is_numeric($_GET['parent']) && isset($_GET['title']))
{
$parent = $_GET['parent'];
$title = mysql_real_escape_string($_GET['title']);
mysql_query("INSERT INTO tree (parent, title) VALUES ('$parent', '$title')");
rebuild_tree(0, 0);
}
function rebuild_tree($parent, $left) {
// the right value of this node is the left value + 1
$right = $left+1;
// get all children of this node
$result = mysql_query('SELECT id FROM tree '.
'WHERE parent="'.$parent.'";');
while ($row = mysql_fetch_array($result)) {
// recursive execution of this function for each
// child of this node
// $right is the current right value, which is
// incremented by the rebuild_tree function
$right = rebuild_tree($row['id'], $right);
}
// we've got the left value, and now that we've processed
// the children of this node we also know the right value
mysql_query('UPDATE tree SET lft='.$left.', rgt='.
$right.' WHERE id="'.$parent.'";');
// return the right value of this node + 1
return $right+1;
}
?>
I hope that helps anyone else looking for the same thing.