ZF2 getServiceLocator in ControllerPlugin class

2019-03-27 18:01发布

问题:

I am trying to get service locator/entity manager in plugin class, How can I get that.

In my controller I am getting it like this.

public function getEntityManager()
{
    if(null === $this->em){
        $this->em = $this->getServiceLocator()->get('doctrine.entitymanager.orm_default');
    }
    return $this->em;
}

public function setEntityManager(EntityManager $em)
{
    $this->em = $em;
}

but in plugin class I am getting error on $this->getServiceLocator() line. because this is not available in plugin class.

How can I do the same so that I can fetch some records and insert few in database in plugin.

I do have MvcEvent $e object in my plugin class, I can make use of this to get entity manager?

I have used this plugin to create my plugin

Any guide will be appriciated.

update:

namespace Auth\Controller\Plugin;

use Zend\Mvc\Controller\Plugin\AbstractPlugin;
use Zend\EventManager\EventInterface as Event;
use Zend\Authentication\AuthenticationService;

use Doctrine\ORM\EntityManager;
use Auth\Entity\User;
use Zend\Mvc\MvcEvent;
class AclPlugin extends AbstractPlugin
{

    /*
    * @var Doctrine\ORM\EntityManager
    */
    protected $em;

    public function checkAcl($e)
    {

        $auth = new AuthenticationService();
        if ($auth->hasIdentity()) {
            $storage = $auth->getStorage()->read();            
            if (!empty($storage->role))
                $role = strtolower ( $storage->role );            
            else 
                $role = "guest";            
        } else {
            $role = "guest";            
        }
        $app = $e->getParam('application');
        $acl          = new \Auth\Acl\AclRules(); 

        $matches      = $e->getRouteMatch();
        $controller   = $matches->getParam('controller');
        $action       = $matches->getParam('action', 'index');

        $resource = strtolower( $controller );
        $permission = strtolower( $action );

        if (!$acl->hasResource($resource)) {
            throw new \Exception('Resource ' . $resource . ' not defined');
        }

        if ($acl->isAllowed($role, $resource, $permission)) {

            $query = $this->getEntityManager($e)->createQuery('SELECT u FROM Auth\Entity\User u');
            $resultIdentities = $query->execute();

            var_dump($resultIdentities);
            exit();


            return;

        } else {
            $matches->setParam('controller', 'Auth\Controller\User'); // redirect
            $matches->setParam('action', 'accessdenied');    

            return;
        }


    }


    public function getEntityManager($e) {

        var_dump($this->getController()); // returns null
        exit();
        if (null === $this->em) {
            $this->em = $this->getController()->getServiceLocator()->get('doctrine.entitymanager.orm_default');

        }
        return $this->em;
    }

    public function setEntityManager(EntityManager $em) {
        $this->em = $em;
    }

}

I am calling above class in module.php

    public function onBootstrap(Event $e) 
    {

        $application = $e->getApplication();        
        $services    = $application->getServiceManager();        

        $eventManager = $e->getApplication()->getEventManager();
        $eventManager->attach('dispatch', array($this, 'loadConfiguration'),101);

    }

public function loadConfiguration(MvcEvent $e)
    {

        $e->getApplication()->getServiceManager()
                  ->get('ControllerPluginManager')->get('AclPlugin')
                  ->checkAcl($e); //pass to the plugin...      

    }

I am registering this plugin in module.config.php

return array(  
 'controllers' => array(
        'invokables' => array(
            'Auth\Controller\User' => 'Auth\Controller\UserController',
        ),
    ), 

    'controller_plugins' => array(
      'invokables' => array(
          'AclPlugin' => 'Auth\Controller\Plugin\AclPlugin',
      ),  
    ),
);

回答1:

What do you mean with "Plugin Class"? In case you're talking abount controller plugins, you can access it using (from the controller plugin's scope): $this->getController()->getServiceLocator()->get('doctrine.entitymanager.orm_default');.

For other classes, I usually create a factory that injects the ServiceManager instance automatically. For example, in the Module class:

public function getServiceConfig()
{
    return array(
        'factories' => array(
            'myServiceClass' => function(ServiceManager $sm) {
                $instance = new Class();
                $instance->setServiceManager($sm);
                // Do some other configuration

                return $instance;
            },
        ),
    );
}

// access it using the ServiceManager where you need it
$myService = $sm->get('myService');


回答2:

changed the above AclPlugin class as below

namespace Auth\Controller\Plugin;

use Zend\Mvc\Controller\Plugin\AbstractPlugin;
use Zend\EventManager\EventInterface as Event;
use Zend\Authentication\AuthenticationService;

use Doctrine\ORM\EntityManager;
use Auth\Entity\User;
use Zend\Mvc\MvcEvent;

use Zend\ServiceManager\ServiceManagerAwareInterface;
use Zend\ServiceManager\ServiceManager;
class AclPlugin extends AbstractPlugin implements ServiceManagerAwareInterface
{

   /*
    * @var Doctrine\ORM\EntityManager
    */
    protected $em;

    protected $sm;

    public function checkAcl($e)
    {

        $this->setServiceManager( $e->getApplication()->getServiceManager() );

        $auth = new AuthenticationService();
        if ($auth->hasIdentity()) {
            $storage = $auth->getStorage()->read();            
            if (!empty($storage->role))
                $role = strtolower ( $storage->role );            
            else 
                $role = "guest";            
        } else {
            $role = "guest";            
        }
        $app = $e->getParam('application');
        $acl          = new \Auth\Acl\AclRules(); 

        $matches      = $e->getRouteMatch();
        $controller   = $matches->getParam('controller');
        $action       = $matches->getParam('action', 'index');

        $resource = strtolower( $controller );
        $permission = strtolower( $action );

        if (!$acl->hasResource($resource)) {
            throw new \Exception('Resource ' . $resource . ' not defined');
        }

        if ($acl->isAllowed($role, $resource, $permission)) {

            $query = $this->getEntityManager($e)->createQuery('SELECT u FROM Auth\Entity\User u');
            $resultIdentities = $query->execute();

            var_dump($resultIdentities);
            foreach ($resultIdentities as $r)
                echo $r->username;
            exit();


            return;

        } else {
            $matches->setParam('controller', 'Auth\Controller\User'); // redirect
            $matches->setParam('action', 'accessdenied');    

            return;
        }

    }



    public function getEntityManager() {

        if (null === $this->em) {
            $this->em = $this->sm->getServiceLocator()->get('doctrine.entitymanager.orm_default');

        }
        return $this->em;
    }

    public function setEntityManager(EntityManager $em) {
        $this->em = $em;
    }

   /**
    * Retrieve service manager instance
    *
    * @return ServiceManager
    */
    public function getServiceManager()
    {
        return $this->sm->getServiceLocator();
    }

    /**
    * Set service manager instance
    *
    * @param ServiceManager $locator
    * @return void
    */
    public function setServiceManager(ServiceManager $serviceManager)
    {
        $this->sm = $serviceManager;
    } 

}


回答3:

Actually getting ServiceManager in controller plugin is quite easy!

Just use: $this->getController()->getServiceLocator()

Example:

namespace Application\Controller\Plugin;

use Zend\Mvc\Controller\Plugin\AbstractPlugin;

class Translate extends AbstractPlugin 
{

    public function __invoke($message, $textDomain = 'default', $locale = null) 
    {
        /** @var \Zend\I18n\Translator\Translator $translator */
        $translator = $this->getController()->getServiceLocator()->get('translator');

        return $translator->translate($message, $textDomain, $locale);
    }
}