Reputation: 23250
My function looks like that. It works but does lots of work (recursively calls itself and does lots of db queries). There must be another way to do same thing but with array (with one query). I can't figure out how to modify this function to get it work with array.
function genMenu($parent, $level, $menu, $utype) {
global $db;
$stmt=$db->prepare("select id, name FROM navigation WHERE parent = ? AND menu=? AND user_type=?") or die($db->error);
$stmt->bind_param("iii", $parent, $menu, $utype) or die($stmt->error);
$stmt->execute() or die($stmt->error);
$stmt->store_result();
/* bind variables to prepared statement */
$stmt->bind_result($id, $name) or die($stmt->error);
if ($level > 0 && $stmt->num_rows > 0) {
echo "\n<ul>\n";
}
while ($stmt->fetch()) {
echo "<li>";
echo '<a href="?page=' . $id . '">' . $name . '</a>';
//display this level's children
genMenu($id, $level+1, $menu, $utype);
echo "</li>\n\n";
}
if ($level > 0 && $stmt->num_rows > 0) {
echo "</ul>\n";
}
$stmt->close();
}
Upvotes: 2
Views: 607
Reputation: 7516
Maybe not what you wanted, but it is great when it comes to trees. You would have to rebuild your table and had some code to output the html, but you would have only one query. It could be worth the effort on the long run.
ie.If you have this menu
# Menu hierarchy: - Home - Product |- Tv |- Radio - About us
It would looks like this in the db.
+----+----------+-----------+-----+-----+ | id | menu | parent_id | lft | rgt | +----+----------+-----------+-----+-----+ | 1 | Home | null | 1 | 2 | +----+----------+-----------+-----+-----+ | 2 | Product | null | 3 | 8 | +----+----------+-----------+-----+-----+ | 3 | Tv | 2 | 4 | 5 | +----+----------+-----------+-----+-----+ | 4 | Radio | 2 | 6 | 7 | +----+----------+-----------+-----+-----+ | 5 | About us | null | 9 | 10 | +----+----------+-----------+-----+-----+
The data could be fetch using a similar query
$select = "SELECT * FROM table_name WHERE lft BETWEEN 3 AND 8;"
To output a specific menu:
- Product |- Tv |- Radio
I know its not exactly the answer your were looking for, but FYI, there are other ways to use hierarchical tree data.
Good luck.
Upvotes: 1
Reputation: 10258
I think the first thing you can fix is removing the WHERE parent = ? clause and then work on the resulting query result, this will make you work a bit more in managing the result but will definitely safe you IO operations.
Using parts of Marc B Solution
$tree = array();
$sql = "select id, parent, name FROM navigation AND menu=? AND user_type=?";
$results = mysql_query($sql) or die(mysql_error());
while(list($id, $parent, $name) = mysql_fetch_assoc($results)) {
$tree[$id] = array('name' => $name, 'children' => array(), 'parent' => $parent);
if (!array_key_exists($tree[$parent]['children'][$id])) {
$tree[$parent]['children'][$id] = $id;
}
}
print_r($tree);
Replace the ? with the actual values, and give that a run, what is your output?
Upvotes: 1
Reputation: 360692
You can build a tree-based array fairly easily, so it'd be one single query and then a bunch of PHP logic to do the array building:
$tree = array();
$sql = "SELECT id, parent, name FROM menu WHERE parent ... etc.... ";
$results = mysql_query($sql) or die(mysql_error());
while(list($id, $parent, $name) = mysql_fetch_assoc($results)) {
$tree[$id] = array('name' => $name, 'children' => array(), 'parent' => $parent);
if (!array_key_exists($tree[$parent]['children'][$id])) {
$tree[$parent]['children'][$id] = $id;
}
}
For this, I'm assuming that your tree has a top-level '0' node. if not, then you'll have to adjust things a bit.
This'd give you a double-linked tree structure. Each node in the tree has a list of its children in the ['children']
sub-array, and each node in the tree also points to its parent via the ['parent']
attribute.
Given a certain starting node, you can traverse back up the tree like this:
$cur_node = 57; // random number
$path = array();
do {
$parent = $tree[$cur_node]['parent'];
$path[] = $parent;
$cur_node = $parent;
} while ($parent != 0);
Upvotes: 2
Reputation: 1905
I wrote in the past an ugly way but with simple SELECT:
I store in text/varchar field strings like this:
/001
/001/001
/001/002
/002
/002/001
/002/001/001
Ignore the hebrew and look in window.aMessages array, to look how it works: http://www.inn.co.il/Forum/Forum.aspx/t394009#4715854
Upvotes: 0