navigationmigrationzend-viewzend-navigationzend-framework3

Migrating ZF2 to ZF3: How to adapt navigation view?


In my ZF2 application I have a this navigation view script:

$routeMatch = $this->getHelperPluginManager()
    ->getServiceLocator()
    ->get('Application')
    ->getMvcEvent()
    ->getRouteMatch();
$currentRoute = $routeMatch instanceof \Zend\Mvc\Router\RouteMatch ? $routeMatch->getMatchedRouteName() : null;
?>
<?php foreach ($this->container as $page) : ?>
<li <?php echo $currentRoute == $page->getRoute() ? ' class="active"' : null;?>>
    <?php echo $this->navigation()->menu()->htmlify($page, true, false) . PHP_EOL; ?>
</li>
<?php endforeach; ?>

Since the getServiceLocator() is now deprecated, I need another way to get the information about the current route into the navigation view script.

This view script gets set as partial and called in the layout.phtml:

echo $this->navigation('navigation')->menu()->setPartial('navigation/default'); 

So I got the idea to pass the need information via a template variable. I created one in the Module#onDispatch(...):

public function onDispatch(MvcEvent $mvcEvent)
{
    $viewModel = $mvcEvent->getApplication()->getMvcEvent()->getViewModel();
    $routeMatch = $mvcEvent->getRouteMatch();
    $viewModel->currentRoute = $routeMatch instanceof RouteMatch
        ? $routeMatch->getMatchedRouteName() : null
    ;
}

Now I can access it in the layout.phtml. But I don't find a way to pass it into the navigation view script, since the Zend\View\Helper\Navigation\Menu#setPartial(...)` doesn's accept any arguments for variables.

How to pass variables (especially the information about the current route) into the navigation view in Zend Framework 3?


Solution

  • The easiest way to do it using DefaultNavigationFactory.

    Lets say we have some routes as the following

    'router' => [
        'routes' => [
            'world' => [
                'type'    => Literal::class,
                'options' => [
                    'route'    => '/world',
                    'defaults' => [
                        'controller' => Controller\IndexController::class,
                        'action'     => 'index',
                    ],
                ],
                'may_terminate' => true,
                'child_routes' => [
                    'country' => [
                        'type' => Literal::class,
                        'options' => [
                            'route' => '/country',
                            'defaults' => [
                                'controller' => Controller\WorldController::class,
                                'action' => 'country',
                            ],
                        ],
                    ],
                ],
            ],
        ],
    ],
    

    Now we would define our navigation configuration under top-level key navigation and enable zend navigation. You may put this code into your config/autoload/global.php

    Depending on the above route configuration our navigation configuration would be like the following

    // configure the navigation
    'navigation' => [
        'default' => [
            [
                'label' => 'Home',
                'route' => 'home',
            ],
            [
                'label' => 'World',
                'route' => 'world', // this should be the route name not route pattern like '/world'
                'pages' => [
                    [
                        'label' => 'Country',
                        'route' => 'world/country',
                    ],
                ],
            ],
        ],
    ],
    
    // Register the navigation
    'service_manager' => [
        'factories' => [
            'navigation' => Zend\Navigation\Service\DefaultNavigationFactory::class,
        ],
    ],
    

    Now we would be able to call the navigation view helper using the top key navigation from the above configuration into the view script. See below

    <div class="collapse navbar-collapse">
        <?php 
            echo $this->navigation('navigation')
                ->menu()
                ->setUlClass('nav navbar-nav')
                ->renderMenu(); 
            ?>
    </div>
    

    That's it!

    The following shows how you can restrict routes to the user and set ACL object or user Role object through the navigation helper's setter methods. Here $this->loggedInUser, $this->acl and $this->userRole has been injected to the view script thus

    <div class="collapse navbar-collapse" id="main-menu">
    
        <?php if ($this->loggedInUser !== null) : ?>
            <?php $this->navigation('navigation')
                    ->findBy('route', 'hello')
                    ->setParams(array('username' => $this->loggedInUser->getUsername())); ?> // If you need to pass any params
    
            <?php $this->navigation('navigation')
                    ->findBy('route', 'world'); ?>
    
        <?php endif; ?>
    
        <?php 
            echo $this->navigation('navigation')
                ->menu()
                ->setUlClass('nav navbar-nav')
                ->setAcl($this->acl) // ACL object
                ->setRole($this->userRole) // Role Object
                ->renderMenu(); 
        ?>
    
    </div>
    

    Hope this would help you!