ZF2-126: Navigation Active class based on router doesn't work

Description

When using navigation, the active path based on the RouterMatch do not work.

As an example (not sure if the urlHelper and routeMatch are required but it seems to be the only way to get it to work):


$navigation ['users'] =  array(
                'label'      => 'Users',
                'title'      => 'Users',
                'type'       => 'uri',
                'urlHelper'  => $urlHelper,
                'routeMatch' => $routeMatch
                'order'      => -100, // make sure home is the first page
                'urlHelper'  => $urlHelper
        );
        $navigation ['users']['pages'] = array(
            array(
                'label'      => 'Users',
                'controller' => 'user',
                'action'     => 'index',
                'urlHelper' => $urlHelper,
                'routeMatch' => $routeMatch,
            ),
            array(
                'label'      => 'Roles',
                'controller' => 'role',
                'urlHelper' => $urlHelper,
                'routeMatch' => $routeMatch,
                'action'     => 'index',
            )
  );

If you navigate to /user the active path is not marked. What seems to be happening is that on Zend\Navigation\Page\Mvc line number 148 the active parameter is set to true. However when the function is called a second time the control is passed to the parent Zend\Navigation\AbstractPage this then checks the _active parameter, and ignores the MVC::active property altogether.

Result is that isActive on line 397 Zend\View\Helper\Navigation\Module always returns false. If I add:


$this->_active = true;

On line 149 in Zend\Navigation\Page\Mvc all seems to work

Comments

Code tags added.

Hi Jeroen, here is an unit test:


/**
 * @group ZF2-126
 */
public function testRenderWithMvcPage()
{
    // Router and route
    $route = new \Zend\Mvc\Router\Http\Segment(
        '/:controller[/:action]',
        array(),
        array(
            'controller' => 'index',
            'action'     => 'index',
        )
    );
    $router = new \Zend\Mvc\Router\Http\TreeRouteStack();
    $router->addRoute('default', $route);

    // Request and route match
    $request = new \Zend\Http\Request();
    $request->setUri('/user');
    $routeMatch = $router->match($request);

    // URL helper
    $urlHelper = new \Zend\View\Helper\Url();
    $urlHelper->setRouter($router);
    $urlHelper->setRouteMatch($routeMatch);

    \Zend\Navigation\Page\Mvc::setDefaultUrlHelper($urlHelper);

    // Navigation container
    $navigation['users'] = array(
        'label'      => 'Users',
        'title'      => 'Users',
        'type'       => 'uri',
        'order'      => -100, // make sure home is the first page
    );

    $navigation['users']['pages'] = array(
       array(
           'label'      => 'Users',
           'controller' => 'user',
           'action'     => 'index',
           'routeMatch' => $routeMatch,
       ),
       array(
           'label'      => 'Roles',
           'controller' => 'role',
           'action'     => 'index',
           'routeMatch' => $routeMatch,
       )
    );

    $container = new \Zend\Navigation\Navigation($navigation);

    // Test
    $expected = '
Users Users Roles '; $actual = $this->_helper->renderMenu($container); $this->assertEquals($expected, $actual); }

Result: Tests passed

Please feel free to reopen this issue if I missed something.

I've abandoned Zend 2.0 since reporting this bug, so I won't be able to confirm. But thanks for looking into it.

Hi Jeroen, can you provide your code so I can reproduce the problem. That would be nice.

Kind regards, Frank

Let me see,

I can't commit all code but let me see what I can provide. What I was attempting to do was create navigation by allowing each module to add entries to a navigation array. I used the event handler to trigger an event that each of the modules could subscribe to. Below is an example of the listener for the access module.

(I cannot currently find how I triggered the event, I seem to have created a controller but I can't seem to find how I manage to call it every time)


<?php

namespace Access\View\Admin;

use Zend\EventManager;

use Zend\EventManager\EventCollection,
    Zend\EventManager\ListenerAggregate,
    Zend\EventManager\StaticEventCollection;

class Listener implements ListenerAggregate
{
    protected $layout;
    protected $listeners = array();
    protected $staticListeners = array();
    protected $view;
    protected $displayExceptions = false;

    public function __construct()
    {
    }

    public function setDisplayExceptionsFlag($flag)
    {
        $this->displayExceptions = (bool) $flag;
        return $this;
    }

    public function displayExceptions()
    {
        return $this->displayExceptions;
    }

    public function attach(EventCollection $events)
    {
        
    }

    public function detach(EventCollection $events)
    {
        
    }
    
    public function registerStaticListeners(StaticEventCollection $events, $locator)
    {
        $handler = $events->attach('adminEventManager', 'buildMenu', array($this, 'buildAdminMenu'), -50);
        $this->staticListeners[] = array('adminEventManager', $handler);
    }

    public function detachStaticListeners(StaticEventCollection $events)
    {
        foreach ($this->staticListeners as $i => $info) {
            list($id, $handler) = $info;
            $events->detach($id, $handler);
            unset($this->staticListeners[$i]);
        }
    }

    public function buildAdminMenu(EventManager\Event  $e)
    {
        $navigation = $e->getParam("navigation");
        $urlHelper = $e->getParam('urlHelper');
        $routeMatch = $e->getParam('routeMatch');
        
        $navigation ['users'] =  array(
                'label'      => 'Users',
                'title'      => 'Users',
                'type'       => 'uri',
                'urlHelper'  => $urlHelper,
                'routeMatch' => $routeMatch,
                'uri'       => '#',
                'image'     => '/ApplicationAdmin/images/nav/users.png'
        );
        $navigation ['users']['pages'] = array(
            array(
                'label'      => 'Users',
                'route' => 'user-list',
                'urlHelper' => $urlHelper,
                'routeMatch' => $routeMatch,
            ),
            array(
                'label'      => 'Roles',
                'route' => 'role-list',
                'urlHelper' => $urlHelper,
                'routeMatch' => $routeMatch,
            ),
             array(
                'label'      => 'Permissions',
                'route' => 'permission-list',
                'urlHelper' => $urlHelper,
                'routeMatch' => $routeMatch,
            ),
        );
        $navigation = $e->setParam("navigation", $navigation);
    }
}

This is the config for that same module


<?php
return array(
    'doctrine' => array(
        'entitypaths' => array(
            'access-entities' => dirname(__DIR__).'/src/Access/Model'
        ),
    ),
    'authentication' => array(
        'password_salt_length' => 22,
        'entity' => 'Access\Model\User',
        'identityProperty' => 'userLogin',
        'credentialProperty' => 'userPassword',
    ),
    
    'routes' => array(
        'user-list' => array(
            'type'    => 'Zend\Mvc\Router\Http\Segment',
            'options' => array(
                'route'    => '/user/list[/sortby/:sortby][/direction/:direction][/page/:page]',
                'constraints' => array(
                    'sortby' => '[a-zA-Z0-9]*',
                    'direction' => '(asc|desc)',
                    'page' => '[0-9]*',
                ),
                'defaults' => array(
                    'controller' => 'UserList',
                    'action'     => 'index',
                    'page' => '1',
                    'direction' => 'asc',
                ),
            ),
        ),
        'user-view' => array(
            'type'    => 'Zend\Mvc\Router\Http\Segment',
            'options' => array(
                'route'    => '/user/view/:id',
                'constraints' => array(
                    'id' => '[0-9]*',
                ),
                'defaults' => array(
                    'controller' => 'user',
                    'action'     => 'view',
                ),
            ),
        ),
         'user-delete' => array(
            'type'    => 'Zend\Mvc\Router\Http\Segment',
            'options' => array(
                'route'    => '/user/delete/:id',
                'constraints' => array(
                    'id' => '[0-9]*',
                ),
                'defaults' => array(
                    'controller' => 'user',
                    'action'     => 'delete',
                ),
            ),
        ),
         'user-edit' => array(
            'type'    => 'Zend\Mvc\Router\Http\Segment',
            'options' => array(
                'route'    => '/user/edit/:id',
                'constraints' => array(
                    'id' => '[0-9]*',
                ),
                'defaults' => array(
                    'controller' => 'user',
                    'action'     => 'view',
                ),
            ),
        ),
        'role-list' => array(
            'type'    => 'Zend\Mvc\Router\Http\Segment',
            'options' => array(
                'route'    => '/role/list[/:page]',
                'constraints' => array(
                    'page' => '[0-9]*',
                ),
                'defaults' => array(
                    'controller' => 'role',
                    'action'     => 'list',
                    'page' => '1',
                ),
            ),
        ),
        
        'role-view' => array(
            'type'    => 'Zend\Mvc\Router\Http\Segment',
            'options' => array(
                'route'    => '/role/view/:id',
                'constraints' => array(
                    'id' => '[0-9]*',
                ),
                'defaults' => array(
                    'controller' => 'role',
                    'action'     => 'view',
                ),
            ),
        ),
         'role-delete' => array(
            'type'    => 'Zend\Mvc\Router\Http\Segment',
            'options' => array(
                'route'    => '/role/delete/:id',
                'constraints' => array(
                    'id' => '[0-9]*',
                ),
                'defaults' => array(
                    'controller' => 'role',
                    'action'     => 'delete',
                ),
            ),
        ),
         'role-edit' => array(
            'type'    => 'Zend\Mvc\Router\Http\Segment',
            'options' => array(
                'route'    => '/role/edit/:id',
                'constraints' => array(
                    'id' => '[0-9]*',
                ),
                'defaults' => array(
                    'controller' => 'role',
                    'action'     => 'edit',
                ),
            ),
        ),
        'permission-list' => array(
            'type'    => 'Zend\Mvc\Router\Http\Segment',
            'options' => array(
                'route'    => '/permissions/list[/:id]',
                'constraints' => array(
                    'id' => '[0-9]*',
                ),
                'defaults' => array(
                    'controller' => 'permission',
                    'action'     => 'list',
                ),
            ),
        ),
        
        'access-admin-login' => array(
            'type' => 'Zend\Mvc\Router\Http\Literal',
            'options' => array(
                'route'    => '/login',
                'defaults' => array(
                    'controller' => 'access-admin-login',
                    'action'     => 'index',
                ),
            ),
        ),
    ),
    'di'=> array(
        'instance' => array(
            'alias' => array(
                'login' => 'Access\Controller\LoginController',
                'authservice' => 'Access\Service\AuthenticationService',
                'user' => 'Access\Controller\UserController',
                'UserList' => 'Access\Controller\UserListController',
                'role' => 'Access\Controller\RoleController',
                'permission' => 'Access\Controller\PermissionController',
            ),
            'Zend\View\PhpRenderer' => array(
                'parameters' => array(
                    'resolver' => 'Zend\View\TemplatePathStack',
                    'options'  => array(
                        'script_paths' => array(
                            'access' => __DIR__ . '/../views',
                        ),
                    ),
                ),
            ),
        ),
    ),
);

Eventually after collecting all the data it is added to the view.


    $menu = ' ';
    $breadcrumb = '';
    if($this->navigationContainer){
        $this->navigation($this->navigationContainer);
        $menu = $this->navigation()->CustomMenu();
        $breadcrumb = $this->navigation()->breadcrumbs()->setSeparator(' » ');
    }

This is when I found the problem described in this bug.

If this is not enough, I will need to do a checkout of an earlier version and submit it to you.

Sorry, I don't quite understand how the code tags work and I can't edit the above comment but I'm sure you can figure it out.

Hi Jeroen, I have reopen this issue and now you can edit your comments. (Click on the pencil right next to your comment.)

Example for the code tags:

`

Done, I was trying ``` which obviously didn't work.

This issue has been closed on Jira and moved to GitHub for issue tracking. To continue following the resolution of this issues, please visit: https://github.com/zendframework/zf2/issues/2447