Module.php中的ZF3依赖注入

时间:2018-09-10 16:24:28

标签: php zend-framework3

我目前正在将ZF2应用程序迁移到ZF3。 大多数情况下,一切进展顺利,但我只能坚持一件事。

在我的Module.php中,我使用zend-permissions-acl进行ACL管理。

class Module
{
protected $defaultLang = 'fr';

public function onBootstrap(MvcEvent $e)
{
    $eventManager        = $e->getApplication()->getEventManager();
    $moduleRouteListener = new ModuleRouteListener();
    $moduleRouteListener->attach($eventManager);

    if (!$e->getRequest() instanceof ConsoleRequest){
        $eventManager->attach(MvcEvent::EVENT_RENDER_ERROR, array($this, 'onRenderError'));
        $eventManager->attach(MvcEvent::EVENT_RENDER, array($this, 'onRender'));
        $eventManager->attach(MvcEvent::EVENT_FINISH, array($this, 'onFinish'));

        $this->initAcl($e);
        $eventManager->attach('route', array($this, 'checkAcl'));
    }
}

public function checkAcl(MvcEvent $e) {
    $app = $e->getApplication();
    $sm  = $app->getServiceManager();
    $route = $e -> getRouteMatch() -> getMatchedRouteName();
    $authService = $sm->get('AuthenticationService');
    $jwtService = $sm->get('JwtService');
    $translator = $sm->get('translator');

    $identity = null;
    try {
        $identity = $jwtService->getIdentity($e->getRequest());
    } catch(\Firebase\JWT\ExpiredException $exception) {
        $response = $e->getResponse();

        $response->setStatusCode(401);
        return $response;
    }

    if(is_null($identity) && $authService->hasIdentity()) { // no header being passed on... we try to use standard validation
        $authService->setJwtMode(false);
        $identity = $authService->getIdentity();
    }

    $userRole = 'default';
    $translator->setLocale($this->defaultLang);
    if(!is_null($identity))
    {
        $userRole = $identity->getType();

        //check if client or prospect
        if($userRole >= User::TYPE_CLIENT)
        {
            $userManagementRight = UserRight::CREATE_USERS;
            if($identity->hasRight($userManagementRight))
                $userRole = 'userManagement';
        }

        $translator->setLocale($identity->getLang());
    }

    if (!$e->getViewModel()->acl->isAllowed($userRole, null, $route)) {
        $response = $e -> getResponse();

        $response->setStatusCode(403);
        return $response;
    }
public function initAcl(MvcEvent $e) {
    //here is list of routes allowed
}
}

我的问题是我仍在使用getServiceManager,因此得到了不建议使用的警告:Usage of Zend\ServiceManager\ServiceManager::getServiceLocator is deprecated since v3.0.0;

基本上,我只需要将依赖项注入Module.php中。 我想否则我将必须直接将checkAcl移至Controller并将ACL注入其中?不确定执行此操作的正确方法是什么。

任何对此的反馈将不胜感激。

此致

罗伯特

1 个答案:

答案 0 :(得分:4)

要解决此问题,您应该使用Listener类和Factory。它还可以帮助您进一步分离问题:)

根据您的代码判断,您似乎很有能力找出问题。因此,我将仅举一个我自己的示例,因此您应该使用自己的代码填写自己(我也有点懒,在我可以复制/粘贴我的代码时不希望重写所有内容在;))


在您的module.config.php中:

'listeners'       => [
    // Listing class here will automatically have them "activated" as listeners
    ActiveSessionListener::class,
],
'service_manager' => [
    'factories' => [
        // The class (might need a) Factory
        ActiveSessionListener::class => ActiveSessionListenerFactory::class,
    ],
],

工厂

<?php

namespace User\Factory\Listener;

use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\ORM\EntityManager;
use Interop\Container\ContainerInterface;
use User\Listener\ActiveSessionListener;
use Zend\Authentication\AuthenticationService;
use Zend\ServiceManager\Factory\FactoryInterface;

class ActiveSessionListenerFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
    {
        /** @var ObjectManager $entityManager */
        $entityManager = $container->get(EntityManager::class);
        /** @var AuthenticationService $authenticationService */
        $authenticationService = $container->get(AuthenticationService::class);

        return new ActiveSessionListener($authenticationService, $entityManager);
    }
}

听众

<?php

namespace User\Listener;

use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\ORM\EntityManager;
use User\Entity\User;
use Zend\Authentication\AuthenticationService;
use Zend\EventManager\Event;
use Zend\EventManager\EventManagerInterface;
use Zend\EventManager\ListenerAggregateInterface;
use Zend\Mvc\MvcEvent;

/**
 * Class ActiveSessionListener
 *
 * @package User\Listener
 *
 * Purpose of this class is to make sure that the identity of an active session becomes managed by the EntityManager.
 * A User Entity must be in a managed state in the event of any changes to the Entity itself or in relations to/from it.
 */
class ActiveSessionListener implements ListenerAggregateInterface
{
    /**
     * @var AuthenticationService
     */
    protected $authenticationService;

    /**
     * @var ObjectManager|EntityManager
     */
    protected $objectManager;

    /**
     * @var array
     */
    protected $listeners = [];

    /**
     * CreatedByUserListener constructor.
     *
     * @param AuthenticationService $authenticationService
     * @param ObjectManager         $objectManager
     */
    public function __construct(AuthenticationService $authenticationService, ObjectManager $objectManager)
    {
        $this->setAuthenticationService($authenticationService);
        $this->setObjectManager($objectManager);
    }

    /**
     * @param EventManagerInterface $events
     */
    public function detach(EventManagerInterface $events)
    {
        foreach ($this->listeners as $index => $listener) {
            if ($events->detach($listener)) {
                unset($this->listeners[$index]);
            }
        }
    }

    /**
     * @param EventManagerInterface $events
     */
    public function attach(EventManagerInterface $events, $priority = 1)
    {
        $events->attach(MvcEvent::EVENT_ROUTE, [$this, 'haveDoctrineManagerUser'], 1000);
    }

    /**
     * @param Event $event
     *
     * @throws \Doctrine\Common\Persistence\Mapping\MappingException
     * @throws \Doctrine\ORM\ORMException
     */
    public function haveDoctrineManagerUser(Event $event)
    {
        if ($this->getAuthenticationService()->hasIdentity()) {
            // Get current unmanaged (by Doctrine) session User
            $identity = $this->getAuthenticationService()->getIdentity();

            // Merge back into a managed state
            $this->getObjectManager()->merge($identity);
            $this->getObjectManager()->clear();

            // Get the now managed Entity & replace the unmanaged session User by the managed User
            $this->getAuthenticationService()->getStorage()->write(
                $this->getObjectManager()->find(User::class, $identity->getId())
            );
        }
    }

    /**
     * @return AuthenticationService
     */
    public function getAuthenticationService() : AuthenticationService
    {
        return $this->authenticationService;
    }

    /**
     * @param AuthenticationService $authenticationService
     *
     * @return ActiveSessionListener
     */
    public function setAuthenticationService(AuthenticationService $authenticationService) : ActiveSessionListener
    {
        $this->authenticationService = $authenticationService;

        return $this;
    }

    /**
     * @return ObjectManager|EntityManager
     */
    public function getObjectManager()
    {
        return $this->objectManager;
    }

    /**
     * @param ObjectManager|EntityManager $objectManager
     *
     * @return ActiveSessionListener
     */
    public function setObjectManager($objectManager)
    {
        $this->objectManager = $objectManager;

        return $this;
    }

}

重要部分:

  • Listener必须实现ListenerAggregateInterface
  • 必须在模块配置的listeners键中激活

就是这样。然后,您有了侦听器的基本构建块。

attach函数外,如果需要,您可以将其余部分放入抽象类中。将使用多个侦听器保存几行(读取:重复代码)。


注意::上面的示例使用普通的 EventManager 。通过对上述代码进行简单的更改,您可以通过将它们附加到 SharedEventManager 来创建“通用”侦听器,如下所示:

/**
 * @param EventManagerInterface $events
 */
public function attach(EventManagerInterface $events, $priority = 1)
{
    $sharedManager = $events->getSharedManager();

    $sharedManager->attach(SomeClass::class, EventConstantClass::SOME_STRING_CONSTANT, [$this, 'callbackFunction']);
}

public function callbackFunction (MvcEvent $event) {...}