3

我昨天也问过这个问题,但是这个问题包括代码。

问题

我的应用程序有多个模块和两种类型的用户帐户,加载了一些模块,其中一些模块是always为用户加载的,application.config.php一些是为用户conditional加载的type Atype B

在阅读了有关 Stack Overflow 的文档和问题后,我了解了 ModuleManager 的一些功能,并开始实现我认为可行的逻辑。

我如何想出一种方法来加载application.config.php [SUCCESS]中不存在但它们的配置不起作用的模块[THE ISSUE]即如果在onBootstrap方法中我获得了ModuleManager服务并且getLoadedModules()我得到了正确加载的所有模块的列表。之后,如果我尝试从该动态加载的模块中获取一些服务,它会引发异常。

Zend\ServiceManager\ServiceManager::get 无法获取或创建 jobs_mapper 的实例

请注意,工厂和所有其他东西都很好,因为如果我从 application.config.php 加载模块,它就可以正常工作

同样,当我尝试从它抛出的动态加载的模块访问任何路由时,404 Not Found这清楚地表明即使模块由 ModuleManager 加载,这些模块的 module.config.php 中的配置也没有加载。

代码

在我的应用程序模块的 Module.php 中,我实现InitProviderInterface并添加了一个方法,在该方法init(ModuleManager $moduleManager)中我捕获了 moduleManager loadModules.post 事件触发器并加载模块

public function init(\Zend\ModuleManager\ModuleManagerInterface $moduleManager)
{
    $eventManager = $moduleManager->getEventManager();
    $eventManager->attach(\Zend\ModuleManager\ModuleEvent::EVENT_LOAD_MODULES_POST, [$this, 'onLoadModulesPost']);
}

然后在同一个类中我删除方法onLoadModulesPost并开始加载我的动态模块

public function onLoadModulesPost(\Zend\ModuleManager\ModuleEvent $event)
{

    /* @var $serviceManager \Zend\ServiceManager\ServiceManager */
    $serviceManager = $event->getParam('ServiceManager');
    $configListener = $event->getConfigListener();

    $authentication = $serviceManager->get('zfcuser_auth_service');

    if ($authentication->getIdentity())
    {
        $moduleManager = $event->getTarget();

        ...
        ...

        $loadedModules = $moduleManager->getModules();
        $configListener = $event->getConfigListener();
        $configuration = $configListener->getMergedConfig(false);

        $modules = $modulesMapper->findAll(['is_agency' => 1, 'is_active' => 1]);

        foreach ($modules as $module)
        {
            if (!array_key_exists($module['module_name'], $loadedModules))
            {
                $loadedModule = $moduleManager->loadModule($module['module_name']);

                //Add modules to the modules array from ModuleManager.php
                $loadedModules[] = $module['module_name'];

                //Get the loaded module
                $module = $moduleManager->getModule($module['module_name']);

                //If module is loaded succesfully, merge the configs
                if (($loadedModule instanceof ConfigProviderInterface) || (is_callable([$loadedModule, 'getConfig'])))
                {
                    $moduleConfig = $module->getConfig();
                    $configuration = ArrayUtils::merge($configuration, $moduleConfig);
                }
            }
        }

        $moduleManager->setModules($loadedModules);
        $configListener->setMergedConfig($configuration);
        $event->setConfigListener($configListener);
    }
}

问题

  • 是否有可能实现我正在尝试的目标?
  • 如果是这样,最好的方法是什么?
  • 我的代码中缺少什么?
4

2 回答 2

3

我认为您在这里尝试执行的操作存在一些基本错误:您尝试基于合并配置加载模块,因此在模块和合并配置之间创建了循环依赖关系。

我建议不要这样做。

相反,如果您有定义要加载应用程序的哪个部分的逻辑,请将其放入config/application.config.php负责检索模块列表的部分。

但是在这个阶段,依赖任何服务还为时过早,因为服务定义也依赖于合并的配置。

另一件要澄清的事情是,您试图根据经过身份验证的用户(请求信息,而不是环境信息)是否符合某个标准来做出这些决定,然后根据该标准修改整个应用程序。

不要那样做:相反,通过在它前面放置一个保护,将决定移动到有条件地启用/禁用的组件中。

于 2017-07-25T17:15:51.890 回答
0

您要求的可以完成,但这并不意味着您应该这样做。

在不了解您正在构建的应用程序的复杂性的情况下提出适当的解决方案是很困难的。

使用守卫肯定有助于解耦你的代码,但是单独使用它并不能解决可伸缩性和可维护性,如果这是一个问题?

我建议使用基于无状态令牌的身份验证。与其在每个应用程序中维护验证逻辑,不如在一个公共位置编写验证逻辑,以便每个请求都可以使用该逻辑,而与应用程序无关。选择反向代理服务器 (Nginx) 来维护验证逻辑(在 Lua 的帮助下)使您可以灵活地使用任何语言开发应用程序。

更重要的是,在负载均衡器级别验证凭据基本上消除了对会话状态的需要,您可以拥有许多单独的服务器,在多个平台和域上运行,重用相同的令牌来验证用户。

识别用户、帐户类型和加载不同的模块就变成了一项微不足道的任务。通过简单地通过环境变量传递令牌信息,它可以在您的config/application.config.php文件中读取,而无需事先访问数据库、缓存或其他服务。

于 2017-07-26T10:30:43.857 回答