ZF2 Dynamic Menu with Zend\\Navigation\\Navigation

2019-03-29 11:04发布

问题:

I want ask you about this problem. What do i need to create Dynamic Menu with Zend\Navigation\Navigation?

In ZF1 i made like this:

$container = new Zend_Navigation();
$pages = array(
array(
    'label'  => 'Save',
    'action' => 'save',
),
array(
    'label'  => 'Delete',
    'action' => 'delete',
),
);
// add two pages
$container->addPages($pages);

and then in view:

$this->navigation()->menu();

But in ZF2 pages are taking from config. Now i create \config\autoload\nav.global.php and here create page array. But i need to do page array in method and send it into navigation helper, but ii dont know how ((

i tried to do this in my controller:

use Zend\Navigation\Navigation;
$pages =array(
        // All navigation-related configuration is collected in the 'navigation' key
        'navigation' => array(
            // The DefaultNavigationFactory we configured in (1) uses 'default' as the sitemap key
            'default' => array(
                // And finally, here is where we define our page hierarchy
                'account' => array(
                    'label' => 'faq',
                    'route' => 'faq',
                    'pages' => array(
                        'news' => array(
                            'label' => 'news',
                            'route' => 'news',
                            ),
                            'manual' => array(
                            'label' => 'manual',
                            'route' => 'manual',
                            ),               
                    ),
                ),
            ),
        ),
    );
$Menu = new Navigation($pages);

and then this in view:

$this->Menu()->menu();

but i have a lot of mistakes...

i think you understand my problem. please help. sorry for my english.

回答1:

Follow these easy steps to create the multilevel menu dynamically Step 1:create a partial menu.phtml file and save it in layout folder or the module,eg application/view/layout/menu.phtml

 <ul  id="menu" >

    <?php foreach ($this->container as $page): ?>

        <li <?= $page->isActive()? 'class="active"' : 'class="drop"' ?>>

            <?php echo $this->navigation()->menu()->htmlify($page). PHP_EOL ?>

     <div class="dropdown_2columns" >


                           <?php  foreach ($page as $catpage) :?>

                    <div  class="col_1" >

                              <h3 <?= $page->isActive()? 'class="active"' : 'class="drop"' ?> >
            <?= $this->navigation()->menu()->htmlify($catpage). PHP_EOL ?>
                   </h3>
                        <ul  >

                           <?php  foreach ($catpage as $subpage) :?>

                           <li  <?= $subpage->isActive()? 'class="active"' : 'class="drop"' ?>>
            <?= $this->navigation()->menu()->htmlify($subpage). PHP_EOL ?>


                           <?php endforeach; ?>
                        </ul>   

                    </div>

                      <?php endforeach; ?>

                </div><!-- End dropdown container -->

                    </li>

                <?php endforeach; ?>
 </ul>

Step 2 in your module.php

public function getServiceConfig()
    {
        return array(
                'initializers' => array(
                        function ($instance, $sm) {
                            if ($instance instanceof \Zend\Db\Adapter\AdapterAwareInterface) {
                                $instance->setDbAdapter($sm->get('Zend\Db\Adapter\Adapter'));
                            }
                        }
                ),
                'invokables' => array(
                        'menu' => 'Application\Model\MenuTable',

                ),

                'factories' => array(
                        'Navigation' => 'Application\Navigation\YourNavigationFactory'
                )
        );
    } 

in src/navigation folder in your module create YourNavigation.php and YourNavigationFactory.php

namespace Application\Navigation;

use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\Navigation\Service\DefaultNavigationFactory;
use Admin\Model\Entity\Tablepages;
class YourNavigation extends DefaultNavigationFactory
{




    protected function getPages(ServiceLocatorInterface $serviceLocator)
    {

        if (null === $this->pages) {

            $fetchMenu = $serviceLocator->get('menu')->fetchAll();


            $configuration['navigation'][$this->getName()] = array();



            foreach($fetchMenu as $key=>$row)
            {

                $subMenu = $serviceLocator->get('menu')->fetchAllSubMenus($row['id']);

           if($subMenu){
              $pages = array();
                foreach($subMenu as $k=>$v)
                {
                    foreach($v as $field=>$value){
                        $page['label'] =$value['heading'];
                        $page['route'] = 'visas';
                        if ($value['path'] == $row['path']){
                        $page['params'] = array('action'=>'index',
                                                 'category'=> $this->$row['path'],

                        );


                        }

                        $subCatMenu = $serviceLocator->get('menu')->fetchAllSubCatMenus($value['id']);

                        $subcatpages = array();
                        $subcatgroup = array();
                        $group = array();
                        if($subCatMenu>0){

                        foreach($subCatMenu as $k=>$v)
                        {
                            foreach($v as $field=>$value1){

                                $subpage['label'] =$value1['heading'];
                                $subpage['route'] = 'visas';
                                if ($value['path'] ==$row['path']){

                                    $subpage['params'] = array('action'=>'index',
                                          'category'=> $row['path'],
                                          'sub_category'=> $value1['path']);


                                }elseif($row['id'] ==76){
                                    $subpage['params'] = array('action'=>'index',
                                            'category'=>$value['path'],
                                            'sub_category'=>$value1['path']);


                                }else{

                                $subpage['params'] = array('action'=>'index',
                                            'category'=> $row['path'],
                                            'sub_category'=> $value['path'],
                                            'id'=> $value1['path']);
                                }

                            }
                            $group[] =$subpage;


                         }

                       $page['pages'] =$group;
                       $pages[] =$page;


                        }


                        }

               }


           }


               $configuration['navigation'][$this->getName()][$row['name']] = array(
                    'label' => $row['name'],

                     'route' => 'visas',
                    'params'       => array(
                            'action' => 'index',
                            'category' => $row['path'],

                    ),

                   'pages' =>  $pages,

                );


            }



            if (!isset($configuration['navigation'])) {

                throw new Exception\InvalidArgumentException('Could not find navigation configuration key');
            }
            if (!isset($configuration['navigation'][$this->getName()])) {

                throw new Exception\InvalidArgumentException(sprintf(
                    'Failed to find a navigation container by the name "%s"',
                    $this->getName()
                ));
            }

            $application = $serviceLocator->get('Application');

            $routeMatch  = $application->getMvcEvent()->getRouteMatch();

            $router      = $application->getMvcEvent()->getRouter();
            $pages       = $this->getPagesFromConfig($configuration['navigation'][$this->getName()]);


            $this->pages = $this->injectComponents($pages, $routeMatch, $router);
        }

        return $this->pages;
    }
}

YourNavigationFactory.php

 namespace Application\Navigation;

    use Zend\ServiceManager\FactoryInterface;
    use Zend\ServiceManager\ServiceLocatorInterface;

        class YourNavigationFactory implements FactoryInterface
        {
            public function createService(ServiceLocatorInterface $serviceLocator)
            {
                $navigation =  new MyNavigation();
                return $navigation->createService($serviceLocator);
            }
        }

in your layout.phtml

 <?php  echo $this->navigation('navigation')->menu()->setPartial('menu')->render();  ?>

to create dynamic sitemap from navigation

    $this->navigation('navigation')
          ->sitemap()
          ->setUseXmlDeclaration(false)
          ->setServerUrl('http://www.yourdomain.com')
          ->setFormatOutput(true);?>

   echo $this->navigation()->menu()->setMinDepth(null)->setMaxDepth(null)->setOnlyActiveBranch(false)->setRenderInvisible(true);

to create breadcrumbs

echo $this->navigation()
                  ->breadcrumbs()
                  ->setLinkLast(true)                 
                  ->setMaxDepth(1)                     
                  ->setSeparator(' ▶' . PHP_EOL);

I Hope it helps you to save your time



回答2:

For some backgrounds you might read this answer on another, but similar question regarding Zend\Navigation. The point is you want MVC pages and MVC pages in Zend Framework 2 need a way to assemble the url and find our if the url is active or not.

Every MVC page has a route name. The route stack routes the request and gets a route match. You must inject this route match into the navigation, so every page could check its own route against the matched one.

Similar for the url assembly. If you want to convert the route name into an url, you need the route stack ('router'). Inject the router in your application too and you are able to assemble.

In short:

use Zend\Navigation\Service\ConstructedNavigationFactory;

class MyController extends AbstractActionController
{

  public function indexAction()
  {
    $config = array(
      // your config here
    );

    $factory    = new ConstructedNavigationFactory($config);
    $navigation = $factory->createService($this->getServiceLocator());

    return new ViewModel(array(
        'navigation' => $navigation;
    ));
  }
}

And similar as above answer, in your view:

<?php echo $this->navigation($navigation)->menu()?>


回答3:

My previous answer is not correct. The following code works. For one page. In controller, edit action:

$page = new \Zend\Navigation\Page\Mvc(array(
    'route' => 'application/default',
    'controller' => 'album',
    'action'     => 'edit',
    'use_route_match' => true,
));

$r = $this->getEvent()->getRouter();
$rm = $this->getEvent()->getRouteMatch();
$page->setRouter($r);
$page->setRouteMatch($rm);

echo $page->isActive() ? 'true' : 'false'; // true
echo $page->getHref(); // /test_app/public/application/album/edit/id1


回答4:

You need to do so

In the controller

$pages = new \Zend\Navigation\Page\Mvc(array(
        'pages'=>
            array(
                'album' => array(
                    'label' => 'Album3',
                    'controller' => 'album',
                    'action' => 'edit',
                    'params' => array('id'=>2),
                    'route' => 'album/default',
                )
            )
));

$navigation = new \Zend\Navigation\Navigation();
$serviceLocator = $this->getServiceLocator()->get('Application');
$routeMatch  = $serviceLocator->getMvcEvent()->getRouteMatch();
$router      = $serviceLocator->getMvcEvent()->getRouter();
$pages->setRouteMatch($routeMatch);
$pages->setDefaultRouter($router);

$navigation->addPage($pages);

In view

<?php echo $this->navigation($this->navigation)->menu() ?>


回答5:

Eremite answer is not really wrong. I have tested all the recommendations given here and actually when the default route have several child_routes mark as default, menus doesn't mark the active flag correctly. So it is needed to pass the matched route as a parameter. But perhaps I'm doing something wrong.

Cheers