Skip navigation.
Home

Hierarchical Menu

I've been coding on experts exchange, testing myself. Here's some relevant code for one of the answers.

They're classes that have been used to generate hierarchical menus.

<?php
/**
 * @package menu
 * @author John Kawakami <johnk---.net>
 * @link http://www.slaptech.net Developed by The Slaptech Collective
 * @copyright 2006 Public Domain
 * @version $Id: Menu.class.php 97 2006-07-27 10:43:40Z johnk $
 *
 * Library to help create hierarchical menus.
 * Use MenuRenderer to display the menus.
 *
 * 
 * $menuBar = new Menu('MenuBar');
 * $fileMenu = $menuBar->addMenu( 'File' );
 * $fileMenu->addUrl( 'Open', '/admin/foo.php' );
 * $fileMenu->addUrl( 'Save', '/admin/bar.php' );
 * $fileMenu->addDivider();
 * $fileMenu->addUrl( 'Close', '/admin/baz.php' );
 * 
 */

include_once('ACL.class.php');
 
class Menu
{
    var $acl;
    var $menu;
    var $menuHash; //fixme - combine these two structures into one
    var $name;
    var $description;
    var $icon;
    var $url;
    var $highlight;

    function Menu( &$acl, $name, $description='', $icon='', $url='' )
    {
        $this->acl            =& $acl;
        $this->menu         = array();
        $this->name         =& $name;
        $this->description     =& $description;
        $this->icon         =& $icon;
        $this->url             =& $url;
        $this->highlight    = false;
    }
    function addObject( &$obj )
    {
        array_push( $this->menu, &$obj );
    }
    function addNamedObject( $name, &$obj )
    {
        $this->menuHash[$name] =& $obj;
        $this->addObject( &$obj );
    }
    /**
     * Utility function.
     */
    function &addMenu( &$acl, $name, $description='', $icon='', $url='' )
    {
        $new = new Menu( &$acl, $name, $description, $icon, $url );
        $this->addObject( $new );
        return $new;
    }
    function &getNamedObject( $name )
    {
        return $this->menuHash[$name];
    }
    function &addUrl( &$acl, $name, $url, $description='', $popup='' )
    {
        $new = new UrlMenuItem( &$acl, $name, $url, $description, $popup );
        $this->addObject( $new );
        return $new;
    }
    function &addDivider()
    {
        $new = new DividerMenuItem();
        $this->addObject( $new );
        return $new;
    }
    function select( $name )
    {
        for( $i=0; $i < count($this->menu); $i++ )
        {
            if ($this->menu[$i]->name==$name)
            {
                return $this->menu[$i];
            }
        }
    }
    function rewind()
    {
        reset($this->menu);
    }
    function &next()
    {
        // check the acl to see if this user can see the next item - fixme
        list( $index, $obj ) = each( $this->menu );
        return $obj;
    }
    function disable()
    {
        $this->enabled = false;
    }
    function enable()
    {
        $this->enabled = true;
    }
    function highlight()
    {
        $this->highlight = true;
    }
}

class UrlMenuItem extends Menu
{
    var $name;
    var $url;
    var $description;
    var $popup;

    function &UrlMenuItem( &$acl, $name, $url, $description='', $popup='' )
    {
        $this->acl            =& $acl;
        $this->name         =& $name;
        $this->url             =& $url;
        $this->description     =& $description;
        $this->popup         =& $popup;
        return $this;
    }

}
class DividerMenuItem extends Menu
{
    function DividerMenuItem()
    {
        $this->name = 'divider';
    }
}


?>
The menus are rendered via another class:
<?php
/**
* @package menu
* @author John Kawakami <johnk----.net>
* @link http://www.slaptech.net Developed by The Slaptech Collective
* @copyright 2006 Public Domain
* @version $Id: MenuRenderer.class.php 92 2006-07-27 09:13:10Z johnk $
*
* Rendering classes for menus. These are kind of like "templates"
* for menus, except they can render hierarchies, portions of menus,
* etc. There's HTML code in here. Yuk.
*/

/**
* Rendering interface. Each renderer must implement the
* url, divider, and menu methods. The menu() method is the heart
* of the renderer.
*/
class MenuRenderer
{
function MenuRenderer() {}
function divider() {}
function url() {}
function menu() {}
function item( $obj )
{
return $obj->name;
}
}

/**
* Renders a menu as an html unordered list (UL).
*/
class HtmlMenuRenderer extends MenuRenderer
{
function HtmlMenuRenderer() {}

function menu( &$menu, $indent=0 )
{
$t = str_repeat( ' ', $indent );
$m =& $menu;
$m->rewind();
if ($m->name != '@')
$output .= "$t<li>";
if ($m->name != '@')
{
if ($m->url)
$output .= "<a href='$m->url'>";
if ($m->icon)
{
$output .= "<img src='$m->icon' border='0' />";
$output .= "<br>";
}
$output .= $m->name."\n";
if ($m->url)
$output .= '</a>';
}
$output .= "$t<ul>\n";
while( $obj =& $m->next() )
{
$class = strtolower(get_class($obj));
// echo "$class<br>";
switch( $class )
{
case 'apmenu':
case 'menu':
$output .= $this->menu( $obj, $indent+4 );
break;
case 'urlmenuitem':
$output .= $this->url( $obj, $indent+4 );
break;
case 'dividermenuitem':
$output .= $this->divider( $obj, $indent+4 );
break;
default:
$output .= $this->item( $obj, $indent+4 );
break;
}
}
$output .= "$t</ul>\n";
if ($m->name != '@')
$output .= "$t</li>\n";
return $output;
}
function divider( &$obj, $indent=0 )
{
$t = str_repeat( ' ', $indent );
return "$t<li>-----------</li>\n";
}
function url( &$obj, $indent=0 )
{
$t = str_repeat( ' ', $indent );
return "$t<li><a href='$obj->url'>$obj->name</a></li>\n";
}
}