在Zend Framework 2中动态加载模块

时间:2017-07-25 06:02:54

标签: php zend-framework2 zend-framework-mvc zend-framework-modules zend-config

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

问题

我的应用程序有多个模块和两种类型的用户帐户,一些模块已加载always,其中application.config.php中存在conditional,其中一些是type A,即一些模块已加载给用户{{ 1}}和一些用户type 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进行delcare并开始加载我的动态模块

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);
    }
}

问题

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

2 个答案:

答案 0 :(得分:3)

我认为你在这里尝试做的事情有一些根本性的错误:你正在尝试基于合并配置加载模块,因此在模块和合并配置之间创建循环依赖。

我会反对这一点。

相反,如果您有定义要加载应用程序的哪个部分的逻辑,请将其放在config/application.config.php中,该'/\[\[.*?&path=`([^`]+?)`.*?\]\]/' 负责检索模块列表。

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

要澄清的另一件事是,您尝试根据身份验证的用户(请求信息,而不是环境信息)是否符合特定条件,然后根据是否修改整个应用程序来做出这些决定在那。

不要这样做:相反,通过在其前面放置一个警卫,将决定移动到有条件启用/禁用的组件中。

答案 1 :(得分:0)

你所要求的是什么,但这并不意味着你应该这样做。

在不知道您正在构建的应用程序的复杂性的情况下建议一个合适的解决方案很困难。

使用警卫肯定有助于解密您的代码,但如果这是一个问题,单独使用它并不能解决可扩展性和可维护性问题?

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

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

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