zendframework / zend-navigation

Navigation component from Zend Framework
BSD 3-Clause "New" or "Revised" License
20 stars 25 forks source link

Documentation seems to be wrong ... #55

Open ksba opened 7 years ago

ksba commented 7 years ago

I found this code snippet in den documenation for the zend-navigation component (ZF3):

Docs » Reference » View Helpers » Intro

The Code snippet provided is not working for me:

<?php
// module/MyModule/Module.php

namespace MyModule;

use Zend\View\HelperPluginManager;
use Zend\Permissions\Acl\Acl;
use Zend\Permissions\Acl\Role\GenericRole;
use Zend\Permissions\Acl\Resource\GenericResource;

class Module
{
    /* ... */
    public function getViewHelperConfig()
    {
        return [
            'factories' => [
                // This will overwrite the native navigation helper
                'navigation' => function(HelperPluginManager $pm) {
                    // Setup ACL:
                    $acl = new Acl();
                    $acl->addRole(new GenericRole('member'));
                    $acl->addRole(new GenericRole('admin'));
                    $acl->addResource(new GenericResource('mvc:admin'));
                    $acl->addResource(new GenericResource('mvc:community.account'));
                    $acl->allow('member', 'mvc:community.account');
                    $acl->allow('admin', null);

                    // Get an instance of the proxy helper
                    $navigation = $pm->get('Zend\View\Helper\Navigation');

                    // Store ACL and role in the proxy helper:
                    $navigation->setAcl($acl);
                    $navigation->setRole('member');

                    // Return the new navigation helper instance
                    return $navigation;
                }
            ]
        ];
    }
    /* ... */
}

First it seems that in ZF3 the HelperPluginManager is not passed to the closure. Instead, I found out that the parent ServiceManager is passed.

If I change it to the code below, then the example is working for me:

class Module
{
    /* ... */
    public function getViewHelperConfig()
    {
        return [
            'factories' => [
                // This will overwrite the native navigation helper
                Helper\Navigation::class => function(\Zend\ServiceManager\ServiceLocatorInterface $serviceManager)
                {
                    $navigationViewHelper = new \Zend\View\Helper\Navigation();
                    $navigationViewHelper->setServiceLocator($serviceManager);

                    // Store ACL and role in the proxy helper:
                    $navigationViewHelper->setAcl($this->acl);
                    $navigationViewHelper->setRole($this->role);

                    // Return the new navigation helper instance
                    return $navigationViewHelper;
                }
            ]
        ];
    }
    /* ... */
}

Am I right? Is the documentation for ZF3 not correct?

froschdesign commented 7 years ago

Am I right? Is the documentation for ZF3 not correct?

You are right. The documentation for ZF3 is wrong, because the Plugin Managers in version 3 of zend-servicemanager have changed.

Thanks for reporting!

froschdesign commented 7 years ago

Btw. there is no need to override the view helper configuration. A (lazy) listener, which listen on the Zend\Mvc\MvcEvent::EVENT_RENDER is a better choice. The navigation is not required on every request.

ksba commented 7 years ago

Thanks for the hint!

May I ask you to provide an example how to use a lazy listener which listen on the "render" Event?

froschdesign commented 7 years ago

May I ask you to provide an example how to use a lazy listener which listen on the "render" Event?

The example uses zend-navigation as module.

config/application.config.php:

return [
    'modules' => [
        'Zend\Navigation',
        // …
    ],
];

config/autoload/global.php:

return [
    'event_manager'   => [
        'lazy_listeners' => [
            [
                'listener' => MyModule\Listener\NavigationListener::class,
                'method'   => 'addAcl',
                'event'    => Zend\Mvc\MvcEvent::EVENT_RENDER,
                'priority' => -100,
            ],
        ],
    ],
];

module/MyModule/src/MyModule/Listener/NavigationListener.php

namespace MyModule\Listener;

use Zend\Mvc\MvcEvent;

class NavigationListener
{
    /**
     * @param MvcEvent $event
     */
    public function addAcl(MvcEvent $event)
    {
        // Get service manager
        $serviceManager = $event->getApplication()->getServiceManager();

        // Get view helper plugin manager
        /** @var \Zend\View\HelperPluginManager $helperPluginManager */
        $helperPluginManager = $serviceManager->get('ViewHelperManager');

        // Get navigation plugin
        /** @var \Zend\View\Helper\Navigation $plugin */
        $plugin = $helperPluginManager->get('navigation');

        // Fetch ACL and role from service manager or identity (authentication service)
        // …

        $plugin->setAcl($acl);
        $plugin->setRole($role);
    }
}

At the moment, there is no factory for Event manager and (lazy) listeners. Therefore, we use the module class in this short example.

module/MyModule/Module.php:

namespace MyModule;

use Zend\EventManager\EventInterface;
use Zend\EventManager\LazyListenerAggregate;
use Zend\ModuleManager\Feature\BootstrapListenerInterface;

class Module implements BootstrapListenerInterface
{
    /**
     * @inheritdoc
     */
    public function onBootstrap(EventInterface $e)
    {
        /** @var \Zend\Mvc\MvcEvent $e */

        $application = $e->getApplication();

        /** @var array $config */
        $config = $application->getServiceManager()->get('config');

        if (array_key_exists('event_manager', $config)
            && is_array($config['event_manager'])
            && array_key_exists('lazy_listeners', $config['event_manager'])
        ) {
            $aggregate = new LazyListenerAggregate(
                $config['event_manager']['lazy_listeners'],
                $application->getServiceManager()
            );
            $aggregate->attach($application->getEventManager());
        }
    }
}

Added benefit: you can add more listeners in your config.

ksba commented 7 years ago

Now I get the Picture. Works like a charm, Thanks a lot!

newmind507 commented 6 years ago

Hi, I add code that written under but get 500 errror in this line $aggregate->attach($application->getEventManager()); . $aggregate - object(Zend\EventManager\LazyListenerAggregate)#166 (4) $application->getEventManager() - object(Zend\EventManager\EventManager)#74 (4) but whan try to attach get 500 error. Can help me somebody?

froschdesign commented 6 years ago

@newmind507 Please provide the complete error message, otherwise we would have to guess.

newmind507 commented 6 years ago

Fatal error: Uncaught Zend\ServiceManager\Exception\ServiceNotFoundException: Unable to resolve service "Listener\NavigationListener" to a factory; are you certain you provided it during configuration? in /home/u850051480/vendor/zendframework/zend-servicemanager/src/ServiceManager.php:681 Stack trace: #0 /home/u850051480/vendor/zendframework/zend-servicemanager/src/ServiceManager.php(757): Zend\ServiceManager\ServiceManager->getFactory('Listener\Naviga...') #1 /home/u850051480/vendor/zendframework/zend-servicemanager/src/ServiceManager.php(200): Zend\ServiceManager\ServiceManager->doCreate('Listener\Naviga...') #2 /home/u850051480/vendor/zendframework/zend-eventmanager/src/LazyListener.php(119): Zend\ServiceManager\ServiceManager->get('Listener\Naviga...') #3 /home/u850051480/vendor/zendframework/zend-eventmanager/src/LazyListener.php(98): Zend\EventManager\LazyListener->fetchListener() #4 /home/u850051480/vendor/zendframework/zend-eventmanager/src/EventManager.php(322): Zend\EventManager\LazyListener->__invoke(Object( in /home/u850051480/vendor/zendframework/zend-servicemanager/src/ServiceManager.php on line 681

froschdesign commented 6 years ago

@newmind507 Please recheck the namespace of your listener and the module class. I have updated to code example, because an error was included. (Application vs. MyModule)

newmind507 commented 6 years ago

Module.php(namespace Application), NavigationListener.php(namespace Application\Listener)

froschdesign commented 6 years ago

Do have also the namespace in your config? The Service Manager says something different in your error message: "Listener\NavigationListener"

newmind507 commented 6 years ago
'event_manager'   => [
    'lazy_listeners' => [
        [
            'listener' => Application\Listener\NavigationListener::class,
            'method'   => 'addAcl',
            'event'    => Zend\Mvc\MvcEvent::EVENT_RENDER,
            'priority' => -100,
        ],
    ],
],

http://aquariunm.esy.es/ - error here

froschdesign commented 6 years ago

Add the listener to your service-manager configuration.

module/Application/config/module.config.php:

'service_manager'    => [
    'factories' => [
        Application\Listener\NavigationListener::class => Zend\ServiceManager\Factory\InvokableFactory::class,
    ],
],

(I'm sorry, at the moment I can not test this behaviour in an application. I'm on the road.)

newmind507 commented 6 years ago

new error http://aquariunm.esy.es/

froschdesign commented 6 years ago

@newmind507 Very simple: add ::class add the end! (see my code example)

Btw. if you need some more support, then please use the forum or the chat. Thanks!

newmind507 commented 6 years ago

http://aquariunm.esy.es/ - still don't want work((

froschdesign commented 6 years ago

@newmind507 Let's continue at the forum. (I have tested it with the skeleton application without problems.)

weierophinney commented 4 years ago

This repository has been closed and moved to laminas/laminas-navigation; a new issue has been opened at https://github.com/laminas/laminas-navigation/issues/3.