Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
313 views
in Technique[技术] by (71.8m points)

php - Loading Modules Dynamically in Zend Framework 2

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.

ZendServiceManagerServiceManager::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(endModuleManagerModuleManagerInterface $moduleManager)
{
    $eventManager = $moduleManager->getEventManager();
    $eventManager->attach(endModuleManagerModuleEvent::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(endModuleManagerModuleEvent $event)
{

    /* @var $serviceManager endServiceManagerServiceManager */
    $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 ?
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...