ZF3 Dynamic Navigation Menu

780 Views Asked by At

I'd like to create navigation menus from SQL data in ZF3 applications; and in the interest of DRY, I want to try to use common functions to query the data. Based on @Crisp's answer to a similar question, if we want to create a dynamic menu from the module illustrated in the Blog tutorial and use functions from ZendDbSqlRepository, it seems that the navigation factory should look like this:

namespace Blog\Factory;

use Zend\Navigation\Service\AbstractNavigationFactory;
use Zend\ServiceManager\ServiceLocatorInterface;

use Blog\Model\ZendDbSqlRepository;

class BlogNavigationFactory 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...
            $postRepository = new ZendDbSqlRepository();
            $pages       = $postRepository->findAllPosts();

            $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';
    }
}

the factory would be added to the service manager like this:

// In module/Blog/config/module.config.php:

return [
    'service_manager' => [
        'aliases' => [ /* ... */ ],
        'factories' => [
            Model\PostRepository::class => InvokableFactory::class,
            Model\ZendDbSqlRepository::class => Factory\ZendDbSqlRepositoryFactory::class,
            Model\PostCommand::class => InvokableFactory::class,
            Model\ZendDbSqlCommand::class => Factory\ZendDbSqlCommandFactory::class,
            'BlogNavigation' => 'Blog\Factory\BlogNavigationFactory',
        ],
    ],
    'controllers'  => [ /* ... */ ],
    'router'       => [ /* ... */ ],
    'view_manager' => [ /* ... */ ],
];

and used in navigation view helpers like this:

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

This doesn't work because the Blog tutorial passes the data through factories and interfaces that the navigation factory would need to reference somehow.

How do I write my navigation factory to use the findAllPosts function from ZendDbSqlRepository?

1

There are 1 best solutions below

0
On

The getPages() method receives the ServiceManager instance (which implements the ServiceLocatorInterface), you can get your repository using it like so

/**
 * @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 repository from the service locator
        $postRepository = $serviceLocator->get(\Blog\Model\ZendDbSqlRepository::class);
        // get your pages from repository
        $pages       = $postRepository->findAllPosts();

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