Внедрение зависимостей ZF3 в Module.php

В настоящее время я переношу приложение ZF2 на ZF3. В основном все идет гладко, но я зациклился на одном.

В моем Module.php у меня есть управление ACL с помощью zend-permissions-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 непосредственно в контроллер и ввести в них ACL? Не уверен, как это сделать правильно.

Мы будем благодарны за любые отзывы по этому поводу.

С уважением,

Роберт

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
1
0
783
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Чтобы решить эту проблему, вы должны использовать класс 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) {...}

Большое спасибо за это, это потрясающий ответ. Завтра протестирую, но я считаю, что это именно то, что мне нужно! :-)

Robert Vionny 11.09.2018 23:23

Еще раз спасибо, это сработало очень хорошо. Единственная проблема, которая у меня была, заключалась в том, что приоритет был установлен на 1000, из-за чего мое событие произошло без RouteMatched. Верните значение по умолчанию 1, и все остальное пройдет гладко.

Robert Vionny 12.09.2018 12:32

Да, это просто приоритет, который вы можете себе дать. Для меня это ActiveSessionListener. На раннем этапе я хочу знать, кто использует мое приложение, поэтому оно запускается раньше с этим приоритетом. С приоритетом 999 я получил прослушиватель авторизации, чтобы убедиться, что пользователь, определенный с приоритетом 1000, проверяется на разрешение на маршруте ;-)

rkeet 12.09.2018 12:36

Другие вопросы по теме