ronnij Posted December 6, 2017 Share Posted December 6, 2017 (edited) Hi, I am having problems getting a multi level menu working and have read a lot of previous forum posts trying to make sense of it and an example like https://forums.phpfreaks.com/topic/303449-php-recursive-multidimensional-array-to-html-nested-code/?hl=%2Bmultidimensional+%2Barray&do=findComment&comment=1544308 should probably tell me everything I need to know, but I simply cannot get my head around this correctly and make it work. I hope there are some experienced coders here who will bare with my n00bness hehe.. My menu items are stored like: mysql> SELECT id, name, parent FROM menu_items; +----+-------------------+--------+ | id | name | parent | +----+-------------------+--------+ | 1 | Programming | 0 | | 2 | PHP | 1 | | 3 | Python | 1 | | 4 | Operating-Systems | 0 | | 5 | Windows 2012 R2 | 4 | | 6 | Linux Mint | 4 | | 7 | Network | 0 | | 8 | Some stuff | 6 | +----+-------------------+--------+ Programming |- PHP |- Python Operating-Systems |- Windows 2012 R2 |- Linux Mint |- Some Stuff Network Today it only supports 1 sub-level because I just put one loop within another like this: $query = "SELECT id, name FROM menu_items WHERE parent = 0"; $result = $link->query($query); if ($result->num_rows > 0) { while ($row = $result->fetch_assoc()) { $children = getMenuChildrenCount($row['id']); $links_count = getLinksCountFromParentId($row['id']); echo "\t\t\t\t\t\t<li class=\"haschildren\"><div><a href=\"links.php?pid={$row['id']}\" class=\"link\">".$row['name']." ({$links_count})</a> <a href=\"#\" class=\"expand\">".$children."<i class=\"fa icon\"></i></a></div>\n"; echo "\t\t\t\t\t\t<ul>\n"; ${query . $row['id']} = "SELECT id, name FROM menu_items WHERE parent = " . $row['id']; ${result . $row['id']} = $link->query(${query . $row['id']}); if (${result . $row['id']}->num_rows > 0) { while (${row . $row['id']} = ${result . $row['id']}->fetch_assoc()) { $links_count = getLinksCountFromParentId(${row . $row['id']}['id']); echo "\t\t\t\t\t\t\t<li><div><a href=\"links.php?pid=".${row . $row['id']}['id']."\" class=\"link\">".${row . $row['id']}['name']." ({$links_count})</a></div></li>\n"; } } echo "\t\t\t\t\t</ul>\n"; echo "\t\t\t\t\t</li>\n"; } } That, of course, is not optimal or the right way to do it.. Can someone please tell me how to come around multi level with X depth? Thank you very much :-) Edited December 6, 2017 by ronnij Quote Link to comment Share on other sites More sharing options...
Solution requinix Posted December 6, 2017 Solution Share Posted December 6, 2017 This sort of parent/child thing can be handled in one of two ways: 1. Recursively. You write a function that displays the menu for a particular parent (or 0). It calls itself recursively on each child in case it has its own children. 2. Linearly with a stack. It's basically recursive but instead of function calls you track everything in an array. #1 is definitely easier. Can you write that function? Take a look at the code in the other thread for an example. It should look something like function whateverYouWantToCallThisThing($link, $parent) { run a query for the children of $parent if there are children { output a <ul> for each child in the result { output the opening <li> and link whateverYouWantTocallThisThing($link, child) output the closing </li> } output a </ul> } }The output will look like <ul><li>Programming<ul> <li>PHP</li> <li>Python</li></ul></li> <li>Operating-Systems<ul> <li>Windows 2012 R2</li> <li>Linux Mint</li> <li>Some Stuff</li></ul></li> <li>Network</li></ul>Yes, you can format it more nicely than that - if you want to put in a bit more effort. 1 Quote Link to comment Share on other sites More sharing options...
Barand Posted December 6, 2017 Share Posted December 6, 2017 read the records and store n an array, indexed by parent $sql = "SELECT id , item , parent FROM mitem"; $res = $db->query($sql); $menu = []; foreach ($res as $item) { $menu[$item['parent']][$item['id']] = $item['item']; } Then use a recursive function to output the items and levels function output_item(&$menu, $parent, $level=0) { if (!isset($menu[$parent]) ) return; foreach ($menu[$parent] as $id =>$item) { $indent = str_repeat('—', $level * 5); echo "$indent$item<br>"; output_item($menu, $id, $level+1); // re-call the function for subitems } } // output the menu output_item($menu, 0); 2 Quote Link to comment Share on other sites More sharing options...
ronnij Posted December 7, 2017 Author Share Posted December 7, 2017 (edited) Thank you very much both of you! Especially your explanatory "code" @requinix, it did the trick for me. So much headache and yet so simple... *sigh* .. 5 minutes after I read it I ended up with this which does exactly what I wanted function showNestedMenu($parent_id) { require 'config.php'; $query = "SELECT id, name, parent FROM menu_items WHERE parent = {$parent_id}"; $result = $link->query($query); if ($result->num_rows > 0) { echo "<ul>\n"; while ($row = $result->fetch_assoc()) { $children = getMenuChildrenCount($row['id']); $links_count = getLinksCountFromParentId($row['id']); if ($children > 0) { echo "\t\t\t\t\t\t\t<li class=\"haschildren\"><div><a href=\"links.php?pid={$row['id']}\" class=\"link\">".$row['name']." ({$links_count})</a> <a href=\"#\" class=\"expand\">".$children."<i class=\"fa icon\"></i></a></div>\n"; showNestedMenu($row['id']); echo "\t\t\t\t\t\t</li>\n"; } else { echo "\t\t\t\t\t\t\t<li><div><a href=\"links.php?pid=".$row['id']."\" class=\"link\">".$row['name']." ({$links_count})</a></div></li>\n"; } } echo "\t\t\t\t\t</ul>\n"; } } showNestedMenu(0); @Barand: I might wanna try your method as well, just to get the understanding :-) Edited December 7, 2017 by ronnij Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.