Search code examples
phpzend-frameworkzend-navigation

Zend Navigation showing all items in menu


I'm just not getting this; I'm using a standard XML-based Zend_Navigation impl, right out the box so-to-speak - and every page seems to have every menu option. I've tried everything - activeOnly, renderSubMenu, renderParent but they all return my either everything or nothing. I'm assuming I'm misunderstanding, because what I want (the items in the "home" node to be visible on the "home" page etc) seems to be what I would have considered the default behaviour. If I have to start setting content to "active", why do you need to specify URL or container settings in your XML - surely Zend "knows" what is active...

As an example, using this page http://my.opera.com/spadille/blog/zend-navigation-with-xml (which is very standard), I would want all the top level nodes to be visible (Home/About/Product/COntact), but only the children of the "active" page. Is that not default behaviour?

Do I need a partial to achieve this?

Many thanks,

Mike

EDIT

Here's the XML

     <?xml version="1.0" encoding="UTF-8"?>
     <configdata>
 <nav>
    <home>
        <label>Home</label>
        <controller>index</controller>
        <action>index</action>
        <module>default</module>
        <route>home</route>
    </home>
    <admin>         
        <label>Admin</label>
        <controller>admin</controller>
        <action>index</action>
        <module>default</module>
        <route>admin</route>
    </admin>
            <results>           
        <label>Results</label>
        <controller>result</controller>
        <action>index</action>
        <module>default</module>
        <route>results</route>
        <pages>
            <t>
            <label>Charts</label>
            <controller>result</controller>
            <action>graph</action>
            <module>default</module>
            <route>charts</route>
        </t>
        </pages>
    </results>
</nav>
    </configdata>

routes.ini

    routes.home.route = "/"
    routes.home.defaults.controller = index
    routes.home.defaults.action = index


    routes.admin.route = "/admin"
    routes.admin.defaults.controller = admin
    routes.admin.defaults.action = index

    routes.results.route = "/results"
    routes.results.defaults.controller = result
    routes.results.defaults.action = index

    routes.charts.route = "/results/charts"
    routes.charts.defaults.controller = result
    routes.charts.defaults.action = chart

And my bootstrap

    protected function _initNavigation()
{
    $this->_bootstrap('layout');
    $layout = $this->getResource('layout');
    $view = $layout->getView();
    $config = new Zend_Config_Xml(
            APPLICATION_PATH . '/configs/navigation.xml','nav');


    $navigation = new Zend_Navigation($config);

    $view->navigation($navigation);
}

And my view. I've tried...

    $this->navigation()->menu()

and then this; The following line hides the sub items of the Results Nav, but when you click on it you only get the Item and the sub item, not the top level too (because of maxDepth)

    $this->navigation()->menu()->renderMenu(null,array("minDepth"=>0,"maxDepth"=>1,"onlyActiveBranch"=>true,"renderParents"=>true))

EDIT.

This gets me what I was after, but feels like a hack? Is this appropriate?

     <div class="top_menu">
            <?php echo $this->navigation()->menu()->renderMenu(null,array("minDepth"=>0,"maxDepth"=>0,"onlyActiveBranch"=>1,"renderParents"=>true)) ?>
        </div>
        <div class="sub_menu">
            <?php echo $this->navigation()->menu()->renderMenu(null,array("minDepth"=>1,"maxDepth"=>4,"onlyActiveBranch"=>true,"renderParents"=>false)) ?>
        </div>

Solution

  • Ok I suspect the "default behaviour" of Zend_Navigation is the use case where the entire menu tree is required to be rendered on every page. In this use case the menu's children will be displayed as drop downs using CSS/JS. In this scenario the "strange" behaviour you described actually makes sense.

    Your use case is different in that you are using a mainmenu along with a submenu. This is similar to a topbar + sidebar implementation. In this scenario it is obviously not desirable for the entire menu tree to be rendered on every page.

    To further confuse the issue it seems that renderSubmenu() has some unexpected behaviour in that it will render the root level of the menu, when an active branch has no children. Some have have reported this behaviour as a bug. Here you will find a comment suggesting something similar to your "hack"

    So in summary, your "hack" seems to be a valid approach to make a single container render correctly for your specific use case. If you really want something more elegant, you could perhaps consider:

    1. Using one of the findBy* methods to "extract" your submenu as new container as per Example 40
    2. Splitting the mainmenu and submenu into separate containers and manage the relationship in a piece of code somewhere
    3. Extending Zend_Navigation_Container to enforce the desired behaviour
    4. Using a partial