3

This should (hopefully) be a pretty easy question for some of you to answer.

I have a working Recursive menu from a mySQL database, now my main problem is:

What is the best way to create the URL? I would prefer to bring in the title of each row like /eggs/milk/bacon/. Eggs being level 0 like: eggs-0, milk-1, bacon-2. Any ideas on how to dynamicly output this?

I am pretty much going for what "cletus" said a few comments down on this question: PHP/MySQL - building a nav menu hierarchy

But I need a bit more explanation on how to do it.

Community
  • 1
  • 1
Davy
  • 83
  • 1
  • 3
  • 9
  • Are you having trouble creating the URL part of the unordered list as described in Cletus' post? – Saem Mar 03 '09 at 16:43
  • Correct, the URL part. I'm not sure how to have them stack, /one/two/three/ etc.. – Davy Mar 03 '09 at 19:26

3 Answers3

4

Well, if you want a hierarchy, be best method I know of is called "Modified Preorder Tree Traversal" that is described in great detail in this Sitepoint article, starts about halfway down.

The main difference from what Guss suggested is that it's a bit more performant and a lot easier to only fetch the part of the tree you're looking for.

mikl
  • 23,749
  • 20
  • 68
  • 89
  • Thanks for the info! I did check out both methods before starting this project however the most rows I would be dealing with is 75 max so Tree Traversal seemed like overkill. However, I am now seeing that Tree traversal would of given me a bit more control. *le sigh.* – Davy Mar 04 '09 at 19:18
2

Unless you plan to modify your menu tree often, pre-storing the required hierarchical URL for each menu item is probably the easiest (for run-time resolution that is).

If you expect the tree to be modified often enough, lets say - through a web interface, then it would be easier to generate the paths every time you read the menu, something like this:

 id | name   | parent
----+--------+-------
 0  | eggs   | NULL
 1  | milk   | 0
 2  | bacon  | 1
 3  | tomato | 0
 4  | lettuce| 1

foreach (query("SELECT * FROM menu ORDER BY parent ASC") as $row) {
  $menuitem = array_merge(array(), $row);
  $menuLookup[$menuitem['id']] &= $menuitem;
  if ($menuitem['parent'] == null) {
    $menuitem['path'] = "/" . $menuitem['name'];
    $menu[] &= $menuitem[];
  } else {
    $parent &= $menuLookup[$menuitem['parent']];
    $menuitem['path'] = $parent['path'] . "/" . $menuitem['name'];
    $parent['menu'][] &= $menuitem;
  }
}

I haven't debugged this code, only tested it for correctness ;-)

Guss
  • 30,470
  • 17
  • 104
  • 128
  • I should of stated that I'm not a php pro but from what I can tell you are basically saying "If 'parent' exists then put 'name' into the parent['path'] array and move on? So this would eventually lead to /milk/bacon/ etc? – Davy Mar 04 '09 at 15:29
  • not exactly - $menu would eventually hold a hierarchy of menu items by placing children into the 'menu' array of their parent. This is standard "un-flatten my list" stuff. – Guss Mar 04 '09 at 16:26
  • The only gimmick here is composing 'path' by prefixing the current name with the parent's 'path', there by recursively building each child's path from the sum of its parents. – Guss Mar 04 '09 at 16:27
  • Awesome, thanks for the help! I will see what I can do. I am still learning how to properly use arrays, I was trying to just use a variable to "stack" the path values recursively. But obviously it would just be overwriting itself (I think, haha!). – Davy Mar 04 '09 at 19:16
  • please note the use of &= to get a reference to the the arrays instead of simple = . The reason is that I don't want to copy the array content - I want to use the same instance so that when I assign data to it, all the references see it. – Guss Mar 05 '09 at 00:44