如何在 onDispatch 事件中使用插件方法?

How to use a plugin method in the onDispatch event?

我有一个查找用户授权的插件。

我在我的 module.config.php 中声明如下:

'controller_plugins' => [
    'factories' => [
        Controller\Plugin\AccessPlugin::class => function($container) {
            return new Controller\Plugin\AccessPlugin(
                $container->get(Model\UserTable::class),
                $container->get(Model\GrantsTable::class),
                $container->get(Model\Authentication::class)
                );
        },
    ],
    'aliases' => [
        'access' => Controller\Plugin\AccessPlugin::class,
    ]
],

在我的 onDispatch(MvcEvent $event) 事件中,我想获取 http 路由参数,查找授权,如果成功,则重定向到正确的路由。

  public function onDispatch(MvcEvent $event)
    {
            $controller = $event->getTarget();
            $controllerName = $event->getRouteMatch()->getParam('controller', null);
            $actionName = $event->getRouteMatch()->getParam('action', null);
            $actionName = str_replace('-', '', lcfirst(ucwords($actionName, '-')));
            $this->access()->checkAccess($controllerName, $actionName);


....

当然找不到插件,还没有加载:

Call to undefined method User\Module::access()

无论如何我都想调用插件方法。在这种情况下是否有可能使用它?像这样:

        $grantplugin = fetch/call the plugin
        $isgranted = $grantplugin->checkAccess($controllerName, $actionName);

感谢任何帮助!

**编辑: 我尝试了 ermengildo 给我的解决方案。但它不起作用,原因是,我还没有与工厂合作过。在一些帮助下,我可能可以学习如何正确地做到这一点。这是我的 nippets:

我在这里找到了两个服务:

我将 module.php 更改为(片段!):

public 函数 onDispatch(MvcEvent $event) {

    $controller = $event->getTarget();
    $controllerName = $event->getRouteMatch()->getParam('controller', null);
    $actionName = $event->getRouteMatch()->getParam('action', null);
    $actionName = str_replace('-', '', lcfirst(ucwords($actionName, '-')));
    $container = $event->getApplication()->getServiceManager();
    $accessService = $container->get(Service\AccessControl::class);
    $accessService->access()->checkAccess($controllerName, $actionName);

最后我尝试将服务声明为工厂:

'service_manager' => [
    'factories' => [
        // Avoid anonymous functions
        Service\AccessControl::class => Service\AccessControlFactory::class,
    ],
],

备注:这里已经有语法警告了: ...无法解析为类型

如果我调试,我得到一个异常:

Unable to resolve service "User\Service\AccessControl" to a factory; are you certain you provided it during configuration?

进一步解释我的module.php中的这一行应该是问题:

 $accessService = $container->get(Service\AccessControl::class);

问题不在于 "the plugin hasn't been loaded yet",而是您不在 控制器 内,而您正试图调用 控制器 插件.

你必须在这里做的是创建一个服务,从服务管理器中检索一个实例,并在该实例上调用该方法。

例子

module.config.php

'service_manager' => [
    'factories' => [
        // Avoid anonymous functions
        \User\Service\AccessControl::class => \User\Service\AccessControlFactory::class
    ]
]

AccessControlFactory

namespace User\Service;

use Zend\ServiceManager\Factory\FactoryInterface;
use User\Service\AccessControl;

class AccessControlFactory implements FactoryInterface {

    /**
     * Factory called
     *
     * @param \Interop\Container\ContainerInterface $container
     * @param string $requestedName
     * @param array|null $options
     * @return TranslatorPlugin
     */
    public function __invoke(\Interop\Container\ContainerInterface $container, $requestedName, array $options = null) {
        $userTable = $container->get(\User\Model\UserTable::class);
        $grantsTable = $container->get(\User\Model\GrantsTable::class);
        $authentication = $container->get(\User\Model\Authentication::class);
        return new AccessControl($userTable, $grantsTable, $authentication);

    }

}

访问控制

namespace User\Service;

use User\Model\UserTable;
use User\Model\GrantsTable;
use User\Model\Authentication;

class AccessControl {

    private $userTable;
    private $grantsTable;
    private $authentication;

    function __construct(UserTable $userTable, GrantsTable $grantsTable, Authentication $authentication) {
        $this->userTable = $userTable;
        $this->grantsTable = $grantsTable;
        $this->authentication = $authentication;

    }

    public function access(){
        // Do your stuff
    }

}

最后,您可以在 Module class 中创建并使用它:

User\Module

public function onDispatch(MvcEvent $event) {
    $controller = $event->getTarget();
    $controllerName = $event->getRouteMatch()->getParam('controller', null);
    $actionName = $event->getRouteMatch()->getParam('action', null);
    $actionName = str_replace('-', '', lcfirst(ucwords($actionName, '-')));
    $container = $event->getApplication()->getServiceManager();
    $accessService = $container->get(\User\Service\AccessControl::class);
    $accessService->access()->checkAccess($controllerName, $actionName);

}

旁注

从您的代码片段中可以很明显地看出您想要实现的目标。我建议您看一下 和 rkeet 所做的评论,因为这是进行访问控制的正确方法。 ;)