Domanda

I need to write a view helper that gets a service and do something with it. I successfully implemented the view helper to have access to the service locator. The problem is that the service I want to get is not being found through the service locator when the __invoke method is called.

The view helper code:

<?php

namespace Application\View\Helper;

use Zend\View\Helper\AbstractHelper,
    Zend\ServiceManager\ServiceLocatorAwareInterface,

    Application\Model;

class LoggedCustomer extends AbstractHelper implements ServiceLocatorAwareInterface
{

    use \Zend\ServiceManager\ServiceLocatorAwareTrait;

    public function __invoke()
    {

        $model = new Model\Customer($this->getServiceLocator());

        return $model->getCurrent();

    }

}

A snippet of the model code:

namespace Application\Model;

use Application\Entity,
    Andreatta\Model\Base as Base;

class Customer extends Base
{

    /**
     * 
     * @return Zend\Authentication\AuthenticationService
     */
    public function getAuthService()
    {

        $serviceLocator = $this->getServiceLocator();

        return $serviceLocator->get('Application\Auth');

    }

    /**
     * 
     * @return Zend\Authentication\Adapter\AdapterInterface
     */
    protected function getAuthAdapter()
    {

        return $this->getAuthService()->getAdapter();

    }

    public function getCurrent()
    {

        $authService = $this->getAuthService();

        if ($authService->hasIdentity())
            return $authService->getIdentity();

        return null;

    }

The snippet from module.config.php:

'service_manager' => array
(

    'factories' => array
    (

        'Application\Auth' => function($sm)
        {

            $authService = $sm->get('doctrine.authenticationservice.application');
            $authService->setStorage( new \Zend\Authentication\Storage\Session('Application\Auth'));

            return $authService;

        },

    ),

),

'view_helpers' => array
(

    'invokables' => array
    (

        'loggedCustomer' => 'Application\View\Helper\LoggedCustomer',

    ),

),

When calling the view helper from any view I get the following:

Zend\View\HelperPluginManager::get was unable to fetch or create an instance for Application\Auth

The weird is that the application is functioning correctly (i.e. this service is being normally used by other parts of the application).

EDIT:

I did some research and I think the only services that I can access through the service manager inside the view helper are the ones registered inside the 'view_manager' section of module.config.php. Does anyone have an idea of how to access the other services?

È stato utile?

Soluzione

$this->getServiceLocator() in view helper can only get u other view helpers you need to use $this->getServiceLocator()->getServiceLocator() to get the application services

Altri suggerimenti

@rafaame: I find a simple way to access service locator in view Helper

We just use:

$this->getView()->getHelperPluginManager()->getServiceLocator(); 

to get a service locator A sample view Helper:

namespace Tmcore\View\Helper;

use Zend\View\Helper\AbstractHelper;

class Resource extends AbstractHelper
{
    public function adminResource()
    {
        $sm = $this->getView()->getHelperPluginManager()->getServiceLocator();
        $adminConfig = $sm->get('ModuleManager')->loadModule('admin')->getConfig();
        return $adminConfig;
    }
}

I guess you are retrieving the Zend\View\HelperPluginManager instead of the correct ServiceManager. Probably you are not injecting it as you should.

That makes sense if thats your complete LoggedCustomer code, since you are not saving the SM. As far as I know, if you implement the ServiceLocatorAwareInterface the SM will be injected, but you have to handle it.

UPDATE:

sorry, i didnt realize you had ServiceLocatorAwareTrait; thats the same.

But, reading http://framework.zend.com/manual/2.0/en/modules/zend.service-manager.quick-start.html i see

By default, the Zend Framework MVC registers an initializer that will inject the ServiceManager instance, which is an implementation of Zend\ServiceManager\ServiceLocatorInterface, into any class implementing Zend\ServiceManager\ServiceLocatorAwareInterface. A simple implementation looks like the following.

So, the service manager is only being injected ... if you implement ServiceLocatorAwareInterface in a controller.

So, you should manually inject the service manager.

for that, what i use to do is to create a factory in Module.php, instead of creating the invokable in the config. for that you implement this function:

   public function getViewHelperConfig()
   {
    return array(
        'factories' => array(
                'loggedCustomer' => function($sm) {


                     $vh = new View\Helper\LoggedCustomer();
                     $vh->setServiceLocator($sm->getServiceLocator());

                      return $vh;

                  }
             );
      }

Also, i wont have the view helper implementing ServiceLocatorAwareInterface, so nothing else is automaticaly injected.

And with this it will work

It appears that the service manager that is injected into the view helper has only the services that are registered within the section 'view_manager' of module configs.

It is possible to inject the "main" service manager by registering the view helper as a factory like this:

'view_helpers' => 
[

    'factories' =>
    [

        'loggedCustomer' => function($pluginManager)
        {

            $serviceLocator = $pluginManager->getServiceLocator();

            $viewHelper = new View\Helper\LoggedCustomer();
            $viewHelper->setServiceLocator($serviceLocator);

            return $viewHelper;

        },

    ]

],

But you have to make sure that you treat it in setServiceLocator method in the view helper. Otherwise the "limited" service manager will be injected into the view helper later on. Like this:

public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
{

    if($this->serviceLocator !== null)
        return $this;

    $this->serviceLocator = $serviceLocator;

    return $this;
}

It fixes the problem, but it appears to be a tremendous hack to me.

In view helpers, if you want to access application services then use

$this->getServiceLocator()->getServiceLocator()
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top