Issues

ZF-6865: Zend_Navigation view helper support for multiple instances

Description

Current implementation of Zend_Navigation view helper only support to handle one instance of Zend_Navigation. Its should serve multiple of navigation instances, similar to placeholder concept. most of the websites contains more than one navigation.

lets say

 
$main = new Zend_Navigation();
$sidebar = new Zend_Navigation();
$view->navigation($main);  // sets the default
$view->navigation("sidebar", $sidebar); //sets the sidebar view
//etc .. for footer, rightclick menu :)
//easy after that access the navigation in the view
$this->navigation("sidebar") ; //access the side bar navigation
$this->navigation(); // access the default navigation

Thanks

Comments

This sounds interesting. Does anyone else have any comments?

What you're requesting needs modifications in the proxy helper that might not be backwards compatible. By the way, is this feature intended for all helpers, or just the proxy helper?

We can achieve this with backwards compatible by change the type check in the proxy view helper method signature like the below prototype


public function navigation(Zend_Navigation_Container $container = null)
// to
public function navigation($container = null, Zend_Navigation_Container $nav = null)
// and add new array to navigation proxy view helper $containers
// if $nav is null then 
//    if $container is a string then call setContainer(containers[$container])
//    if $container is Zend_Navigation_Container then call  setContainer($container)
// else
//    $container must be string then store $nav in the $containers array 
//    then call setContainer(containers[$container])

I believe by this way there is no need to change all the helpers because the mechanism to change the container already exist.

Because of the mentioned problem, at the moment I have to refuse to use this component, because on my site I have 3 menus with different content. Hope that this issue will be resolved as fast as possible in the next version.

more readable prototype \


public function navigation($container = 'default', Zend_Navigation_Container $navigation = null) {
    if($navigation != null) {
         $this->_containers[$container] = $navigation;
    } elseif ($container instanceof Zend_Navigation_Container) {
         $this->_containers['default'] = $navigation = $container;
    } elseif (isset($this->_containers[$container])) {
         $navigation = $this->_containers[$container];
    } elseif($container == 'default') {
         // Maybe better modify getContainer to getContainer($id = null)
         // to allow multi-navs to be stored in Zend_Registry by resources etc...
         // Keys for example: Zend_Navigation_Default, Zend_Navigation_Sidebar, Zend_Navigation_Footer ..
         $this->_containers[$container] = $navigation = $this->getContainer();
    } else {
         $this->_containers[$container] = $navigation = new Zend_Navigation();
    }
    if (null !== $navigation) {
         $this->setContainer($navigation);
    }
    return $this;
}

any news?

I quickly tried creating a custom view helper that extends the pre built view helper (merely calling the navigation method from my custom view helper's appropriate method) to no avail.

So when I have some time I'll look into both the view helper and zend_navigation to see what methods I'll need to override. However with this line of thought, its hard to be confident about the future compatibility side of things.

I need multiple instances of zend_navigation, per page on my multiple module project.

I would like to see this resolved, because i think it is natural to use Zend_Navigation for site's main navigation and a separate instance of Zend_Navigation for a language selection menu or any other kind of "menu" not directly related to site's main navigation.

I have not put any work/thoughts into this issue since my last comment. I'm still awaiting more community feedback on possible solutions and requirements.

To be honest, this is not exactly a major issue/drawback with the view helper. You can always store as many container instances you like, e.g. in a registry, and simply render menus for those separately.

Example:


<?php
$topNav = Zend_Registry::get('myTopNav');
$sideNav = Zend_Registry::get('mySideNav');
echo $this->navigation()->menu()->renderMenu($topNav);
echo $this->navigation()->menu()->renderMenu($sideNav);

If you want to take it further, you could store the containers in the proxy helper dynamically, and simply do:


<?php
$proxy = $this->navigation();
echo $proxy->menu($proxy->topNav);
echo $proxy->menu($proxy->sideNav);

I have been trying to get two menu to render on the same page, but i am haveing many problems. I tried Mr. Skoglung's example from above, but am not able to get it to work. Here is what I am doing. Being both menus will be the same on through the application i am putting this code in the Bootstrap.php file for the application: Zend_Registry::set('utility',$container->findByLabel('Page 1')); Zend_Registry::set('main',$container->findByLabel('Page 2')); And this code I am putting in the layout script: <?php echo $this->navigation()->menu()->renderMenu(Zend_Registry::get('utility')); ?> <?php echo $this->navigation()->menu()->renderMenu(Zend_Registry::get('main')); ?> The container I am using is something I copied out of the online documentation online. For the sake of completeness, I will post it here: $container = new Zend_Navigation(array( array( 'label' => 'Page 1', 'uri' => 'page-1', 'foo' => 'bar', 'pages' => array( array( 'label' => 'Page 1.1', 'uri' => 'page-1.1', 'foo' => 'bar', ), array( 'label' => 'Page 1.2', 'uri' => 'page-1.2', 'class' => 'my-class', ), array( 'type' => 'uri', 'label' => 'Page 1.3', 'uri' => 'page-1.3', 'action' => 'about' ) ) ), array( 'label' => 'Page 2', 'id' => 'page_2_and_3', 'class' => 'my-class', 'module' => 'page2', 'controller' => 'index', 'action' => 'page1' ), array( 'label' => 'Page 3', 'id' => 'page_2_and_3', 'module' => 'page3', 'controller' => 'index' )));

Onces I have this working, I would like to add ACL to it to display only certain parts of the menu.

The above code render the first menu, but not the second. I am at a loss. I have tryin several thing to no avail. Any help would be greatly apreciated.

Thank you in advance. Troy

Closing this issue now to clean up the issue tracker. For general help, consult the mailing lists or IRC.

I would be grateful, if you could add the described possibility.

The current implementation is not really good and seperated menus are used quite often I think.

I'd like to add, that this extension would make sense for example for the use of breadcrumbs.

Now if you have several navigations, only the one added to the view will work for breadcrumbs. That's not really nice...

Robin, regarding your example


<?php
$proxy = $this->navigation();
echo $proxy->menu($proxy->topNav);
echo $proxy->menu($proxy->sideNav);

given the absence of __get and __set magic methods in the proxy helper, I can only assume you're directly assigning new, public properties. Don't you think this is a little hacky (it's one of those PHP "features" I've never been happy with)? Perhaps you could implement the aforementioned magic methods to manipulate a protected $_namedContainers array for named navigation containers.

For anyone else trying to get it accomplished, this seems to be a good way to do it:


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

calling render (or even renderMenu) directly with an navigation container does not change the internal navigation object of the view helper and simply renders whatever is provided.