Issues

ZF-8402: Zend_View_Helper_Navigation_Menu ignores pages visiblity

Description

From Reference Guide section 37.2.1. Common page features:

{quote} visible | bool | TRUE | Whether page should be visible for the user, or just be a part of the structure. Invisible pages are skipped by view helpers. {quote}

I tried to take advantage of this property, adding the following element in the navigation xml file

...
    Usuários
        Clique para visualizar os usuários registrados.usersindexuserRegistrar usuário
                Clique para registrar um novo usuário.usersnewuserEditar usuário
                Clique para editar um usuário.usersedituser
                *false*
            
...

but looks like this property isn't properly handled by navigation helpers.

My call for sub menu rendering is as follows:

<?php echo $this->navigation()->menu()->setOnlyActiveBranch(true)
                                      ->setRenderParents(false)
                                      ->setRenderInvisible(false) ?>

Zend_View_Helper_Navigation_Menu doesn't seems to check which a page is visible or not before rendering. A look in the Zend_View_Helper_Navigation_Helper interface shown that there is a method called setRenderInvisible and this is honored by the Zend_View_Helper_Navigation_HelperAbstract class but doesn't seems to be used in the Zend_View_Helper_Navigation_Menu component. A search for the 'visible' string in the component's source code don't return anything.

To help to understand the issue, I followed the navigation helper rendering flow:

Zend_View_Helper_Navigation helpers proxy to the appropriated helper, menu in this case;

Zend_View_Helper_Navigation_Menu return itself;

setOnlyActiveBranch() is called;

The $_onlyActiveBranch is defined;

setRenderParents() is called;

The $_renderParents is defined;

setRenderInvisible() is called from Zend_View_Helper_Navigation_HelperAbstract;

The $_renderInvisible is defined;

Zend_View_Helper_Navigation_Menu calls __toString() - inherited from Zend_View_Helper_Navigation_HelperAbstract;

Zend_View_Helper_Navigation_Menu calls render() - also inherited from Zend_View_Helper_Navigation_HelperAbstract;

Zend_View_Helper_Navigation_Menu calls renderMenu - no partial specified;

_renderDeepestMenu() is called - as onlyActiveBranch is true and renderParents is false. The $_renderInvisible is not used;

Maybe there is missing additional check for the visible property before rendering pages.

Comments

I have the same problem as you, Bruno. I found that the "visible" tag is not being set properly by the Zend_Navigation_xyz class(es). Working through the code systematically resulted in reaching the setVisible() method under Zend_Navigation_Page, which is expected. What was not expected, however, was that the method was designed as:


public function setVisible($visible = true)
{
    $this->_visible = (bool) $visible;

    return $this;
}

The page properties, especially if read from a config INI/XML file, are usually in the form of strings. The boolean value of a string that isn't empty and isn't "0" is true. Thus, anytime you tried to set a page invisible via a string representation for false (i.e. "false" or "FALSE"), the function sets the property to true since this is the value returned when type-casting a non-null, non-empty, non-zero string to a boolean value.

Here's the fix:


public function setVisible($visible = true)
{
    if (is_string($visible) &&
        (strtolower($visible) == 'false' || !((bool)$visible))
    {
        $this->_visible = false;
    }
    else
    {
        $this->_visible = (bool) $visible;
    }

    return $this;
}

Very good, at the first impression your solution is fine.

Did you test this solution in a running application? Were you able to hide the pages by setting the visible property for false?

I will make some tests as soon as possible.

Thanks :)

@Bruno In my web application I was trying to hide certain links in my navigation menu from showing, but I couldn't remove the links from my XML file completely because I wanted navigation->breadcrumbs() to still function properly for these pages.

So, yes, I am using the code posted above and so far I haven't run into any issues. Of course, I haven't tested the code incessantly for input validation purposes, but assuming you type 0, 1, false, or true within the tags in your INI/XML file nothing should break. I might have to go through the Page.php file to ensure that other setter methods don't have bugs either.