I solved this by writing my own navigation menu view helper that extends the one included with the framework. It could go further with optimization, but this is at least working.
Here's the code:
PHP Code:
class AOneFiveThree_View_Helper_Navigation_FilteringMenu extends Zend_View_Helper_Navigation_Menu {
/**
* View helper entry point:
* Retrieves helper and optionally sets container to operate on
*
* @param Zend_Navigation_Container $container [optional] container to
* operate on
* @return Zend_View_Helper_Navigation_Menu fluent interface,
* returns self
*/
public function filteringMenu(Zend_Navigation_Container $container = null) {
if (null !== $container) {
$this->setContainer($container);
}
return $this;
}
/**
* Renders menu
*
* Implements {@link Zend_View_Helper_Navigation_Helper::render()}.
*
* If a partial view is registered in the helper, the menu will be rendered
* using the given partial script. Unlike
* Zend_View_Helper_Navigation_Menu::render(), pages will be filtered based
* on visibility and ACL before being passed to the view partial script.
* If no partial is registered, the menu will be rendered as an 'ul' element
* by the helper's internal method.
*
* @see renderPartial()
* @see renderMenu()
*
* @param Zend_Navigation_Container $container [optional] container to
* render. Default is to
* render the container
* registered in the helper.
* @return string helper output
*/
public function render(Zend_Navigation_Container $container = null) {
if (null === $container) {
$container = $this->getContainer();
}
if ($partial = $this->getPartial()) {
return $this->__filterRestrictedPages($container)
->renderPartial($container, $partial);
} else {
return $this->renderMenu($container);
}
}
/**
* Filters out invisible and ACL based restricted pages
*
* @access protected
* @param Zend_Navigation_Container $container
* @return Zend_Navigation_Container
*/
protected function __filterRestrictedPages(Zend_Navigation_Container $container) {
// Need to clone the container as we will be removing pages from the
// actual container within the recursive iterator loop. Removing
// elements from the object we're iterating over *while* iterating will
// trip up the iterator.
$iterator = new RecursiveIteratorIterator(clone $container,
RecursiveIteratorIterator::SELF_FIRST);
foreach ($iterator as $page) {
/* @var $page Zend_Navigation_Page_Mvc */
if (!$this->accept($page)) {
$container->removePage($page);
}
}
return $this;
}
In order to use the custom menu, you need to add the helper path to your view (replace the AOneFiveThree with your own library or application namespace):
PHP Code:
// In your view-script.phtml
$this->addHelperPath('AOneFiveThree/View/Helper/Navigation', 'AOneFiveThree_View_Helper_Navigation_');
Then, to load the helper, tell it to user a view partial for rendering and render it out:
PHP Code:
$filteringMenu = $this->navigation()->FilteringMenu();
$filteringMenu->setPartial('partials/default-navigation.phtml');
echo $filteringMenu;
And of course, prior to all of this, you need to expose your navigation object, ACL object and the current role to the navigation helper somewhere (probably your bootstrap or a controller plugin). Each page in your navigation object needs to have a resource defined that matches the resources in your ACL for the menu helper to properly filter out restricted pages. The framework reference guide goes over all of this.
PHP Code:
// Assuming $navigation is your navigation object
// Expose the navigation object to the navigation view helper
Zend_Layout::getMvcInstance()
->getView()
->navigation($navigation);
// Assuming $acl is your $acl object and $role is the current ACL role in use
// Expose the acl and role to the view navigation helper so it knows which items to
// filter
Zend_Layout::getMvcInstance()
->getView()
->navigation()
->setAcl($acl)
->setRole($role);
I can explain this in more detail if anyone wants, just let me know.
Edit: I realize this only works on a shallow navigation
Last edited by ryan.horn (2009-11-28 22:29:23)