Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typo3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 重构对每个Zf2控制器操作的一些调用_Php_Architecture_Zend Framework2_Refactoring - Fatal编程技术网

Php 重构对每个Zf2控制器操作的一些调用

Php 重构对每个Zf2控制器操作的一些调用,php,architecture,zend-framework2,refactoring,Php,Architecture,Zend Framework2,Refactoring,我需要做一个自定义的isgrated方法(不使用来自社区的Rbac或acl模块)。因此,我有一个提供功能的服务。但是这个代码: if (!$this->userService->isGrantedCustom($this->session->offsetGet('cod_lvl'), 'ZF_INV_HOM')) { throw new \Exception("you_are_not_allowed", 1); } …在我的每个控制器和每个操作中都是重复的。参数

我需要做一个自定义的
isgrated
方法(不使用来自社区的Rbac或acl模块)。因此,我有一个提供功能的服务。但是这个代码:

if (!$this->userService->isGrantedCustom($this->session->offsetGet('cod_lvl'), 'ZF_INV_HOM')) {
    throw new \Exception("you_are_not_allowed", 1);
}
…在我的每个控制器和每个操作中都是重复的。参数的变化当然取决于权限(
'ZF_INV_HOM'
'ZF_TODO_DELETE'
…)

我认为在调用控制器之前编写这些代码不是一个坏主意,但我不知道什么是最佳解决方案(最佳体系结构),以及如何将这些参数传递给它(我考虑了控制器上的注释,但如何处理?)


关键是,如果我必须修改此代码,我无法想象要修改数百次,对于每个控制器,我的每个操作,我都需要将此代码放在一个位置。

通过将事件侦听器附加到SharedEventManager,您可以将所有控制器作为目标,并在一个位置进行授权检查

在这种情况下,目标是
Zend\Mvc\Controller\AbstractActionController
,这意味着任何扩展它的控制器都将执行侦听器。此侦听器的高优先级意味着它在目标控制器操作之前执行,从而使您有机会处理任何未经授权的请求

public function onBootstrap(MvcEvent $event)
{
    $application  = $event->getApplication();
    $eventManager = $application->getEventManager()->getSharedManager();

    $eventManager->attach(
        \Zend\Mvc\Controller\AbstractActionController::class, // Identity of the target controller
        MvcEvent::EVENT_DISPATCH,
        [$this, 'isAllowed'],
        1000  // high priority
    );
}
在每个控制器中,都需要某种方式来确定正在访问哪个“资源”

例如,它可以实现这个接口

interface ResourceInterface
{
    // Return a unique key representing the resource
    public function getResourceId();
}
然后,侦听器可能看起来像这样

public function isAllowed(MvcEvent $event)
{
    $serviceManager = $event->getApplication()->getServiceManager();

    // We need the 'current' user identity
    $authService = $serviceManager->get('Zend\Authentication\AuthenticationService');
    $identity = $authService->getIdentity();

    // The service that performs the authorization
    $userService = $serviceManager->get('MyModule\Service\UserService');

    // The target controller is itself a resource (the thing we want to access)
    // in this example it returns an resource id so we know what we want to access
    // but you could also get this 'id' from the request or config etc
    $controller = $event->getTarget();

    if ($controller instanceof ResourceInterface) {
        $resourceName = $controller->getResourceId();

        // Test the authorization, is UserX allowed resource ID Y
        if (empty($resourceName) || $userService->isGrantedCustom($identity, $resourceName)) {
            // early exit for success
            return;
        } else {
           // Denied; perhaps trigger a new custom event or return a response
        }
    }

}

通过将事件侦听器附加到SharedEventManager,您可以将所有控制器作为目标,并在一个位置进行授权检查

在这种情况下,目标是
Zend\Mvc\Controller\AbstractActionController
,这意味着任何扩展它的控制器都将执行侦听器。此侦听器的高优先级意味着它在目标控制器操作之前执行,从而使您有机会处理任何未经授权的请求

public function onBootstrap(MvcEvent $event)
{
    $application  = $event->getApplication();
    $eventManager = $application->getEventManager()->getSharedManager();

    $eventManager->attach(
        \Zend\Mvc\Controller\AbstractActionController::class, // Identity of the target controller
        MvcEvent::EVENT_DISPATCH,
        [$this, 'isAllowed'],
        1000  // high priority
    );
}
在每个控制器中,都需要某种方式来确定正在访问哪个“资源”

例如,它可以实现这个接口

interface ResourceInterface
{
    // Return a unique key representing the resource
    public function getResourceId();
}
然后,侦听器可能看起来像这样

public function isAllowed(MvcEvent $event)
{
    $serviceManager = $event->getApplication()->getServiceManager();

    // We need the 'current' user identity
    $authService = $serviceManager->get('Zend\Authentication\AuthenticationService');
    $identity = $authService->getIdentity();

    // The service that performs the authorization
    $userService = $serviceManager->get('MyModule\Service\UserService');

    // The target controller is itself a resource (the thing we want to access)
    // in this example it returns an resource id so we know what we want to access
    // but you could also get this 'id' from the request or config etc
    $controller = $event->getTarget();

    if ($controller instanceof ResourceInterface) {
        $resourceName = $controller->getResourceId();

        // Test the authorization, is UserX allowed resource ID Y
        if (empty($resourceName) || $userService->isGrantedCustom($identity, $resourceName)) {
            // early exit for success
            return;
        } else {
           // Denied; perhaps trigger a new custom event or return a response
        }
    }

}

如果您不想让所有这些代码污染您的模块,您还可以创建一个侦听器类,并在引导方法中仅附加侦听器:

<?php

namespace Application\Listener;

use Application\Service\UserService;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\Mvc\MvcEvent;
use Zend\EventManager\SharedEventManagerInterface;
use Zend\EventManager\SharedListenerAggregateInterface;
use Zend\Authentication\AuthenticationServiceInterface;

class IsAllowedListener implements SharedListenerAggregateInterface
{
    /**
     * @var AuthenticationServiceInterface
     */
    protected $authService;

    /**
     * @var UserService
     */
    protected $userService;

    /**
     * @var \Zend\Stdlib\CallbackHandler[]
     */
    protected $sharedListeners = array();

    /**
     * @param SharedEventManagerInterface $events
     */
    public function attachShared(SharedEventManagerInterface $events)
    {
        $this->sharedListeners[] = $events->attach(AbstractActionController::class, MvcEvent::EVENT_DISPATCH, array($this, 'isAllowed'), 1000);
    }

    public function __construct(AuthenticationServiceInterface $authService, UserService $userService ){
        $this->authService = $authService;
        $this->userService = $userService;
    }

    /**
     * @param MvcEvent $event
     */
    protected function isAllowed(MvcEvent $event)
    {
        $authService = $this->getAuthService();
        $identity = $authService->getIdentity();

        $userService = $this->getUserService();

        if($userService->isGrantedCustom()){
            // User is granted we can return
            return;
        }

        // Return not allowed response
    }

    /**
     * @return AuthenticationServiceInterface
     */
    public function getAuthService()
    {
        return $this->authService;
    }

    /**
     * @param AuthenticationServiceInterface $authService
     */
    public function setAuthService(AuthenticationServiceInterface $authService)
    {
        $this->authService = $authService;
    }

    /**
     * @return UserService
     */
    public function getUserService()
    {
        return $this->userService;
    }

    /**
     * @param UserService $userService
     */
    public function setUserService(AuthenticationServiceInterface $userService)
    {
        $this->userService = $userService;
    }
}
然后在引导中:

public function onBootstrap(EventInterface $event)
{
    $application    = $event->getTarget();
    $serviceManager = $application->getServiceManager();
    $eventManager   = $application->getEventManager();
    $sharedEventManager = $eventManager->getSharedManager();
    $isAllowedListener = $serviceManager->get('Application\Listener\IsAllowedListener')
    $sharedEventManager->attachAggregate($isAllowedListener);
}
您还可以创建一个特定的类,而不是使用
AbstractActionController::class
,这样您将只侦听该类的实例


因此,例如
AbstractIsAllowedActionController::class
或类似的东西。

如果您不想用所有这些代码污染您的模块,您还可以创建一个侦听器类,并在引导方法中只附加侦听器:

<?php

namespace Application\Listener;

use Application\Service\UserService;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\Mvc\MvcEvent;
use Zend\EventManager\SharedEventManagerInterface;
use Zend\EventManager\SharedListenerAggregateInterface;
use Zend\Authentication\AuthenticationServiceInterface;

class IsAllowedListener implements SharedListenerAggregateInterface
{
    /**
     * @var AuthenticationServiceInterface
     */
    protected $authService;

    /**
     * @var UserService
     */
    protected $userService;

    /**
     * @var \Zend\Stdlib\CallbackHandler[]
     */
    protected $sharedListeners = array();

    /**
     * @param SharedEventManagerInterface $events
     */
    public function attachShared(SharedEventManagerInterface $events)
    {
        $this->sharedListeners[] = $events->attach(AbstractActionController::class, MvcEvent::EVENT_DISPATCH, array($this, 'isAllowed'), 1000);
    }

    public function __construct(AuthenticationServiceInterface $authService, UserService $userService ){
        $this->authService = $authService;
        $this->userService = $userService;
    }

    /**
     * @param MvcEvent $event
     */
    protected function isAllowed(MvcEvent $event)
    {
        $authService = $this->getAuthService();
        $identity = $authService->getIdentity();

        $userService = $this->getUserService();

        if($userService->isGrantedCustom()){
            // User is granted we can return
            return;
        }

        // Return not allowed response
    }

    /**
     * @return AuthenticationServiceInterface
     */
    public function getAuthService()
    {
        return $this->authService;
    }

    /**
     * @param AuthenticationServiceInterface $authService
     */
    public function setAuthService(AuthenticationServiceInterface $authService)
    {
        $this->authService = $authService;
    }

    /**
     * @return UserService
     */
    public function getUserService()
    {
        return $this->userService;
    }

    /**
     * @param UserService $userService
     */
    public function setUserService(AuthenticationServiceInterface $userService)
    {
        $this->userService = $userService;
    }
}
然后在引导中:

public function onBootstrap(EventInterface $event)
{
    $application    = $event->getTarget();
    $serviceManager = $application->getServiceManager();
    $eventManager   = $application->getEventManager();
    $sharedEventManager = $eventManager->getSharedManager();
    $isAllowedListener = $serviceManager->get('Application\Listener\IsAllowedListener')
    $sharedEventManager->attachAggregate($isAllowedListener);
}
您还可以创建一个特定的类,而不是使用
AbstractActionController::class
,这样您将只侦听该类的实例


例如,
AbstractIsAllowedActionController::class
或类似的东西。

从哪里可以获得ZF_INV_HOM参数?您应该将其连接到事件管理器。每个控制器都有一个被授予访问权限的权限名称,其在操作控制器本身中定义,并且与数据库中我的用户(自定义RBAC)的权限相匹配。您从何处获取ZF_INV_HOM参数?您应该将其连接到事件管理器。每个控制器都有一个权限名称,用于授予对其的访问权限,其在操作控制器本身中定义,并且与数据库中我的用户(自定义RBAC)的权限相匹配。我对高优先级有疑问,您确定1000高于-1000吗?我无法明确说明此链接和Listeners上的优先级不应在isAllowed(MvcEvent$event)
中,如果($event->getTarget()instanceof ResourceInterface){/*…*/}
@venca如果您是正确的,您需要检查。我已经添加了它。@Hooli直截了当地说:attach()的第三个参数是优先级值。这个数字越高,监听器执行的越早;它越低,执行得越晚。该值默认为1,值将按给定优先级内注册的顺序触发。我对高优先级有疑问,您确定1000高于-1000吗?我无法明确说明此链接和Listeners上的优先级不应在isAllowed(MvcEvent$event)
中,如果($event->getTarget()instanceof ResourceInterface){/*…*/}
@venca如果您是正确的,您需要检查。我已经添加了它。@Hooli直截了当地说:attach()的第三个参数是优先级值。这个数字越高,监听器执行的越早;它越低,执行得越晚。该值默认为1,值将按给定优先级内注册的顺序触发。+1这是最好的方法;您封装了侦听器逻辑,并使用服务工厂处理其依赖项。您说得对,根据您的评论,您涵盖了我的所有询问。谢谢:)@AlexP也谢谢+1这是最好的方法;您封装了侦听器逻辑,并使用服务工厂处理其依赖项。您说得对,根据您的评论,您涵盖了我的所有询问。谢谢:)@AlexP也谢谢