简体   繁体   中英

Hierarchical tree menu - PHP / MySQL

In working on a dynamic menu w/ CRUD I have been having some trouble with the finishing touches. It works, but there are some extra tags getting inserted where there shouldn't be and can't figure out how to clean it up before I share it with the world. I used this as a starting point, then changed it to work with an accordion menu ( http://www.phpro.org/tutorials/Simple-Mysql-PHP-Menu.html ).

Below is the data from the table (I changed the names on the first 2 fields to get it to fit in the SO format from menu_item_id to id, and from menu_parent_id to pid).

id  pid    menu_item_name         menu_url  sortorder status 
1      0    Settings                            0   ACTIVE
2      5    Grid Demo            grid.php           ACTIVE
3      5    setGridOptions       gridoptions.php    ACTIVE
4      1    Menu Items           adminmenu.php  1   ACTIVE
5      0    Grid Settings                       100 ACTIVE
6      1    General Settings     settings.php   100 ACTIVE

Here is the PHP that connects to the mysql database and creates the hierarchical tree array to make it work:

include 'db.php';
$sql = "SELECT * FROM menu_items WHERE status = \"ACTIVE\" ORDER BY sortorder, menu_item_name";
$query = $db->query($sql);


while($data = $query->fetch(PDO::FETCH_ASSOC))
   // loop over the results
    {
        // Assign by reference
        $thisref = &$refs[ $data['menu_item_id'] ];

        // add the the menu parent
        $thisref['menu_item_id'] = $data['menu_item_id'];
        $thisref['menu_parent_id'] = $data['menu_parent_id'];
        $thisref['menu_item_name'] = $data['menu_item_name'];
        $thisref['menu_url'] = $data['menu_url'];

        // if there is no parent id
        if ($data['menu_parent_id'] == 0)
        {
            $list[ $data['menu_item_id'] ] = &$thisref;
        }
        else
        {
            $refs[ $data['menu_parent_id'] ]['children'][ $data['menu_item_id'] ] = &$thisref;
        }
    }

    function create_list( $arr )
    {
        $html = "";
        foreach ($arr as $key=>$v) 
        {
            if ($v['menu_parent_id'] == '0')
            {
             $html .= '<a class="menuitem submenuheader" href="'. $v['menu_url'] .'">'.$v['menu_item_name']."</a>\n";
             $html .= "<div class=\"submenu\">\n<ul>\n";
             $html .= "<li>" . create_list($v['children']) . "</li>";
             $html .= "</ul>\n";
            }
            else{
             $html .= '<li><a id="' . $v['menu_item_id'] . '">'.$v['menu_item_name']."</a></li>\n";
                }
            }
        $html .= "</div>\n";
        return $html;
    }
echo "<div class=\"glossymenu\">";
    echo create_list( $list );
echo "</div>";

When I run it, it outputs the following:

<div class="glossymenu"><a class="menuitem submenuheader">Settings</a>
<div class="submenu">
<ul>
<li><li><a id="4">Menu Items</a></li>
<li><a id="6">General Settings</a></li>
</div>
</li></ul>
<a class="menuitem submenuheader" href="">Grid Settings</a>
<div class="submenu">
<ul>
<li><li><a id="2">Grid Demo</a></li>
<li><a id="3">setGridOptions</a></li>
</div>
</li></ul>
</div>
</div>  

As you can see there are extra <li> tags, the </ul> is in the wrong spot (should be after the </div> ) Other than that, it is working great.

The other thing I can't figure out is if I have a root menu item with no children, I would love it to have a different output like

<a id="8">No Children Menu Item</a>
Instead of:
<a class="menuitem submenuheader">No Children Menu Item</a>

The second example would create the make it show up the little (+/-) for expanding and contracting and wouldn't allow me to click on it. For clarification on the <a> tags, I am using javascript to do a .get() based off the id which is why there is no href or url shown.

UPDATE

It is working correctly and I posted it on Github for anyone that wants it. https://github.com/ajhalls/php-accordian-menu

Try this :

<?php
include 'db.php';

$sql = "SELECT * FROM menu_items WHERE status = 'ACTIVE' ORDER BY pid ASC, sortorder ASC, menu_item_name ASC";
$query = $db->query($sql);

$menu_items = array();

while($data = $query->fetch(PDO::FETCH_ASSOC)) {
    if($data['pid'] == 0) {
        $menu_items[$data['id']] = array();
        $menu_items[$data['id']]['id'] = $data['id'];
        $menu_items[$data['id']]['name'] = $data['menu_item_name'];
        $menu_items[$data['id']]['url'] = $data['menu_url'];
        $menu_items[$data['id']]['children'] = array();
    } else if($data['pid'] != 0) {
        $tmp = array();
        $tmp['id'] = $data['id'];
        $tmp['name'] = $data['menu_item_name'];
        $tmp['url'] = $data['menu_url'];

        array_push($menu_items[$data['pid']]['children'],$tmp);
        unset($tmp);
    }
}

function create_list($arr)
{
    $html = "";
    foreach($arr as $key => $value) {
        if(count($value['children']) > 0) {
            $html .= '  <a class="menuitem submenuheader" href="'. $value['url'] .'">'.$value['name'].'</a>
                        <div class="submenu">
                        <ul>';

            foreach($value['children'] AS $child) {
                $html .= '  <li>
                                <a id="'.$child['id'].'">'.$child['name'].'</a>
                            </li>';
            }

            $html .= '  </ul>
                        </div>';
        } else{
            $html .= '  <a id="'.$value['id'].'">'.$value['name'].'</a>';
        }
    }

    return $html;
}

echo "<div class=\"glossymenu\">";
    echo create_list($menu_items);
echo "</div>";
?>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM