8
votes

I want to use the navigation helper to build my navigation menus using Acl. The Acl part I have working fine.

I now want to be able to display a few different types of navigation. E.g. admin-nav, side-nav, new-nav, etc. I cannot find anything about this in the docs. Only how to set the navigation and then use that one navigation object repeatedly within a layout or view.

I tried something similar to this - having two different containers, with different arrays of pages, then setting these containers in the registry. Then from within my view and/or layout calling navigation and passing it a container:

<?php echo $this->navigation(Zend_Registry::get("news-nav")) ?>

The above is called in my news view, the following is called in my layout

<?php echo $this->navigation(Zend_Registry::get("admin-nav")) ?>

This works fine for all my pages, apart from the news page. On my news page the nav for news is displayed twice, once in the layout and once in the news view. The admin nav is never displayed and seems to be overwritten by the news nav.

I could be going about this completely the wrong way, if so please let me know a better way. If this method seems fine, can someone help me sort out why the news nav is being displayed in the layout and in the news view.

Thanks for your time

Jake

3

3 Answers

10
votes

I have had this exact same issue. I just create multiple instances of Zend_Navigation_Container in my controllers for each of the menus I need, pass them to the view and then render them by passing the objects directly to the menu render method. As follows:

In the controller:

$this->view->menu1 = new Zend_Navigation_Container();
$this->view->menu2 = new Zend_Navigation_Container();

In the view:

$this->navigation()->menu()->renderMenu($this->menu1);
$this->navigation()->menu()->renderMenu($this->menu2);

You could even customise each one (by inserting method calls after the initial menu() call:

$this->navigation()->menu()->setUlClass('my_first_menu')->renderMenu($this->menu1);
$this->navigation()->menu()->setUlClass('my_second_menu')->renderMenu($this->menu2);
1
votes

or you can shorten syntax

$this->menu($this->menu1);
1
votes

I just ran into this issue of needing multiple navigations and in the process discovered your problem and it is actually a bug in the Zend_View_Helper_Navigation_HelperAbstract.

Line 516:

public function __toString()
{
    try {
        return $this->render();
    } catch (Exception $e) {
        $msg = get_class($e) . ': ' . $e->getMessage();
        trigger_error($msg, E_USER_ERROR);
        return '';
    }
}

The problem here is that if you don't explicitly call $this->navigation->render($container) or a magic method like $this->navigation()->menu($container) then the call to render ends up not getting a container passed to it.

This in turn causes the default view helper for navigation, which is menu, to be pulled from the registry (in which case it will use the last given container), or instantiated on the spot (which causes there to be no container).

This is my simple fix which calls getContainer on __toString.

Line 516:

public function __toString()
{
    try {
        return $this->render($this->getContainer());
    } catch (Exception $e) {
        $msg = get_class($e) . ': ' . $e->getMessage();
        trigger_error($msg, E_USER_ERROR);
        return '';
    }
}

Looking through all of the helper files related to Navigation it is clear that the intention was to call getContainer. It is also clear that this isn't an issue if you call the menu view helper either directly or via the navigation magic method.

Once you change that line above you should be able to call $this->navigation($container) and render multiple navigations without having to resort to calling the menu helper directly.