zend-framework2zend-routezend-navigationzend-config

ZF2 - Injecting pages to navigation before controller is called


I'm creating a dynamic Application in which the content is added through a CMS. Inside the CMS, I'm setting a db entry which states what module to use for each content page.

NodeId, ParentNodeId, Name_de, Name_en, ModuleName, foreignkey_ContentLinks,

in this table entries look as follows: 6, 1, Veranstaltung-21-02-2013, Event-21-02-2013, Events, 682

The entire tree should end up in my navigation (and perfectly also in my routing). I do not want to add it in some controller, because my Application consists of a whole bunch of Modules and I want to access that Info across all my Modules.

I already tried injecting it in the global.php, but to no avail because I can't my db adapter or any other important classes at that stage.

Any ideas or links to best practices?


Solution

  • The navigation containers are composed by factory classes. The easiest approach is to write your own factory and have the getPages() method fetch pages from a database instead of from config. If you extend from the AbstractNavigationFactory you only need to write a couple of methods.

    <?php
    namespace Application\Navigation\Service;
    
    use Zend\Navigation\Service\AbstractNavigationFactory;
    use Zend\ServiceManager\ServiceLocatorInterface;
    
    class CmsNavigationFactory extends AbstractNavigationFactory
    {
        /**
         * @param ServiceLocatorInterface $serviceLocator
         * @return array
         * @throws \Zend\Navigation\Exception\InvalidArgumentException
         */
        protected function getPages(ServiceLocatorInterface $serviceLocator)
        {
            if (null === $this->pages) {
    
                $application = $serviceLocator->get('Application');
                $routeMatch  = $application->getMvcEvent()->getRouteMatch();
                $router      = $application->getMvcEvent()->getRouter();
    
                // get your pages from wherever...
                $pages       = $this->getPagesFromDB();
    
                $this->pages = $this->injectComponents($pages, $routeMatch, $router);
            }
            return $this->pages;
        }
    
        public function getName()
        { 
             // this isn't used if fetching from db, it's just here to keep the abstract factory happy
             return 'cms';
        }
    }
    

    Add the factory to the service manager, just like you would for other containers

    'service_manager' => array(
        'factories' => array(
            'CmsNavigation' => 'Application\Navigation\Service\CmsNavigationFactory',
        ),
    ),
    

    And use it with the navigation view helpers in the same way

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