在Zend Framework 2中动态加载模块 [英] Loading Modules Dynamically in Zend Framework 2

查看:82
本文介绍了在Zend Framework 2中动态加载模块的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我昨天也问过这个问题,但是其中包含代码.

问题

我的应用程序具有多个模块和2种类型的用户帐户,某些模块已加载always,这些模块存在于application.config.php中,其中某些模块是conditional,即某些模块是为用户type A加载的,而某些模块是为用户type B

在阅读了有关Stack Overflow的文档和问题之后,我了解了ModuleManager的一些功能,并开始实现我可能会用到的逻辑.

我如何找到一种方法来加载application.config.php [成功] 中不存在的模块,但是它们的配置不起作用 [问题] ,即如果在onBootstrap方法中,我得到了ModuleManager服务,并做了getLoadedModules()我得到了正确加载的所有模块的列表.然后,如果我尝试从该动态加载的模块中获取某些服务,则会引发异常.

Zend \ ServiceManager \ ServiceManager :: get无法获取Jobs_mapper或为其创建实例

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

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

代码

在我的应用程序模块的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);
    }
}

问题

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

解决方案

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

我不建议这样做.

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

但是在此阶段,依赖任何服务为时过早,因为服务定义也取决于合并的配置.

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

不要这样做:相反,通过在其前面放置防护,将决定移至要有条件地启用/禁用的组件中.

I have asked this question yesterday as well, but this one includes code.

Issue

My application have multiple modules and 2 types of user accounts, Some modules are loaded always which are present in application.config.php some of them are conditional i.e. some are loaded for user type A and some for user type B

After going through documentations and questions on Stack Overflow, I understand some of ModuleManager functionalities and started implementing the logic that I though might work.

Some how I figured out a way to load the modules that are not present in application.config.php [SUCCESS] but their configuration is not working [THE ISSUE] i.e. if in onBootstrap method I get the ModuleManager service and do getLoadedModules() I get the list of all the modules correctly loaded. Afterwards if I try to get some service from that dynamically loaded module, it throws exception.

Zend\ServiceManager\ServiceManager::get was unable to fetch or create an instance for jobs_mapper

Please note that, the factories and all other stuff are perfectly fine because if I load the module from application.config.php it works fine

Similarly when I try to access any route from the dynamically loaded module it throws 404 Not Found which made it clear that the configuration from module.config.php of these modules are not loading even though the module is loaded by ModuleManager.

Code

In Module.php of my Application module I implemented InitProviderInterface and added a method init(ModuleManager $moduleManager) where I catch the moduleManager loadModules.post event trigger and load modules

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

Then in the same class I delcare the method onLoadModulesPost and start loading my dynamic modules

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

Questions

  • Is it possible to achieve what I am trying ?
  • If so, what is the best way ?
  • What am I missing in my code ?

解决方案

I think there is some fundamental mistake in what you are trying to do here: you are trying to load modules based on merged configuration, and therefore creating a cyclic dependency between modules and merged configuration.

I would advise against this.

Instead, if you have logic that defines which part of an application is to be loaded, put it in config/application.config.php, which is responsible for retrieving the list of modules.

At this stage though, it is too early to depend on any service, as service definition depends on the merged configuration too.

Another thing to clarify is that you are trying to take these decisions depending on whether the authenticated user (request information, rather than environment information) matches a certain criteria, and then modifying the entire application based on that.

Don't do that: instead, move the decision into the component that is to be enabled/disabled conditionally, by putting a guard in front of it.

这篇关于在Zend Framework 2中动态加载模块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆