Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP/MySQL - building a nav menu hierarchy

So the final menu will look something like this:

Item B
    Item B-1
        Item B-1-2
        Item B-1-1
Item A
    SubItem A-1
    SubItem A-2
Item C

Based on the following DB records:

id        menu_title          parent_menu_id    menu_level    weight
1         Item A                0                           1                     1
2         Item B                0                           1                     0
3         Item C                0                           1                     2
4         SubItem A-2       1                           2                     1
5         Item B-1             2                           2                     0
6         Item B-1-1          5                           3                     1
7         SubItem A-1       1                           2                     0
8         Item B-1-2          5                           3                     0

How would I go about displaying? My guess is it'll involve storing all the items into a multidimensional array, then looping through it somehow...

like image 399
Matt Avatar asked Dec 03 '22 16:12

Matt


2 Answers

Hierarchical data is somewhat annoying in a relationsal database (excluding Oracle, which has operators in START WITH/CONNECT BY to deal with this). There are basically two models: adjacency list and nested sets.

You've chosen adjacency sets, which is what I typically do too. It's far easier to change than the nested set model, although the nested set model can be retrieved in the correct order in a single query. Adjacency lists can't be. You'll need to build an intermediate data structure (tree) and then convert that into a list.

What I would do (and have done recently in fact) is:

  • select the entire menu contents in one query ordered by parent ID;
  • Build a tree of the menu structure using associative arrays or classes/objects;
  • Walk that tree to create nested unordered lists; and
  • Use a jQuery plug-in like Superfish to turn that list into a menu.

You build something like this:

$menu = array(
  array(
    'name' => 'Home',
    'url' => '/home',
  ),
  array(
    'name' => 'Account',
    'url' => '/account',
    'children' => array(
      'name' => 'Profile',
      'url' => '/account/profile',
    ),
  ),
  // etc
);

and convert it into this:

<ul class="menu">;
  <li><a href="/">Home</a></li>
  <li><a href="/account">Account Services</a>
    <ul>
      <li><a href="/account/profile">Profile</a></li>
...

The PHP for generating the menu array from is reasonably straightforward but a bit finnicky to solve. You use a recursive tree-walking function that builds the HTML nested list markup but will leave it's implementation as an exercise for the reader. :)

like image 161
cletus Avatar answered Dec 11 '22 17:12

cletus


Dealing with the data structure as you have it will often involve recursion or multiple queries to build the tree.

Have you considered other ways of storing a hierarchy? Check out modified pre-order traversal - here's a nice PHP based article about this.

like image 34
Paul Dixon Avatar answered Dec 11 '22 16:12

Paul Dixon