【问题标题】:How to get a reference to the service manager inside the Module's init method (ZF2)?如何在模块的 init 方法(ZF2)中获取对服务管理器的引用?
【发布时间】:2013-10-22 19:58:53
【问题描述】:

我需要在任何MvcEvent::EVENT_BOOTSTRAP 侦听器执行之前执行一些代码。显然Module::onBootstrap 不是一个选项。我以以下代码结束:

class Module
{

    function init(\Zend\ModuleManager\ModuleManager $moduleManager)
    {
        $moduleManager->getEventManager()->attach(
                MvcEvent::EVENT_BOOTSTRAP, array(ClassX, 'StaticMethodOfClassX'), 20000);
    }

}

我不想硬编码array(ClassX, 'StaticMethodOfClassX') 引用,而是从服务管理器获取它。我的问题是我不知道如何在模块的 init 方法中获取服务管理器引用。有什么帮助吗?或者这在 ZF2 现在是不可能的?无论此架构或意见的任何变体都将受到赞赏;)

编辑:

我将澄清“显然 Module::onBootstrap 不是一个选项”,因为可能不是那么微不足道;)

当事件MvcEvent::EVENT_BOOTSTRAP 被触发时,模块Module::onBootstrap 方法被执行,但是每个模块的Module::onBootstrap 方法与该事件的附件依赖于加载模块的顺序。由于,特定Module::onBootstrap 方法的执行顺序取决于存在哪些其他模块以及其他模块如何影响该特定模块的加载顺序。此外,任何附加到MvcEvent::EVENT_BOOTSTRAP 事件的优先级大于1 的侦听器都将在任何模块Module::onBootstrap 方法之前执行,例如ViewManager::onBootstrap 侦听器。所以,要实现我想要的

我需要先执行一些代码 MvcEvent::EVENT_BOOTSTRAP监听器获取执行

模块 obBootstrap 方法不是一个选项。

【问题讨论】:

  • 为什么不能使用onBootstrap?
  • @TimFountain 感谢蒂姆的提问。我编辑我的问题以解释为什么不。再次感谢。

标签: events module zend-framework2 servicemanager


【解决方案1】:

这是一篇非常古老的帖子,但由于没有人接受任何答案,而且我最近需要实现同样的目标,所以我想我会分享我的解决方案。

我需要在触发 Bootstrap 事件之前访问 ServiceManager 的原因是,我可以使用从数据库中检索到的值来操作合并的配置。

问题

Zend documentation 中的示例显示了如何操作合并的配置,但在特定时间服务管理器为空,因此无法检索数据库适配器等内容。

解决方案

在您的模块类中,实现接口InitProviderInterface并添加适当的方法。

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

EVENT_LOAD_MODULES_POST 事件将在 EVENT_MERGE_CONFIG 事件之后但在 EVENT_BOOTSTRAP 事件触发之前被调用。同样在这个特定时间,ServiceManager 将包含您想要访问的所有工厂、可调用类。

您的回调方法可能类似于。

public function onLoadModulesPost(ModuleEvent $event)
{
    /* @var $serviceManager \Zend\ServiceManager\ServiceManager */
    $serviceManager = $event->getParam('ServiceManager');
    $configListener = $event->getConfigListener();
    $configuration = $configListener->getMergedConfig(false);

    $someService = $serviceManager->get('Your/Custom/Service');
    $information = $someService->fetchSomeInformation();
    $configuration = array_merge($configuration, $information);

    $configListener->setMergedConfig($configuration);
    $event->setConfigListener($configListener);
    $serviceManager->setAllowOverride(true);
    $serviceManager->setService('Config', $configuration);
    $serviceManager->setAllowOverride(false);
}

【讨论】:

  • 嗨 adamdyson,我正在努力按照您建议的方式加载模块,模块已加载但它们的配置似乎不起作用,当我尝试去路由一些动态加载的模块时给出错误 404,告诉我们配置未加载或正常工作,在这方面有什么建议吗?
  • 很高兴为您提供帮助,但我需要更多信息。我倾向于通过消除过程来解决这些情况,那么您尝试过什么?遵循我发布的示例时,合并后的配置是什么样的?是否加载了任何模块配置?
  • 感谢您的回复。我已将其作为问题发布,您可以查看一下吗?你好stackoverflow.com/questions/45295059/…
  • 好的,我现在意识到您提出的问题与我在这里解决的问题完全不同。如果我想出解决您问题的方法,我会通知您。
  • 在我进一步研究之前,您可以先尝试禁用配置和模块缓存,还添加更新服务管理器:$serviceManager->setAllowOverride(true); $serviceManager->setService('config', $configuration); $serviceManager->setAllowOverride(false);
【解决方案2】:

你可以从 MvcEvent 中得到它

$locator = $event->getTarget()->getServiceLocator()->get('YourObject')

如果您无权访问该事件,您可以在引导时将该事件设置为 Module 类的属性,然后随时在您的 init 方法中使用它。

 public function onBootstrap($event) {
        $this->setMvcEvent($event);
 }

function init(\Zend\ModuleManager\ModuleManager $moduleManager)
{
    $locator = $this->mvc_event->getTarget()->getServiceLocator()->get('YourClass');
    $moduleManager->getEventManager()->attach(
            MvcEvent::EVENT_BOOTSTRAP, array(ClassX, 'StaticMethodOfClassX'), 20000);
}

【讨论】:

  • 感谢您的回复,但请阅读我的问题,我写了“显然 Module::onBootstrap 不是一个选项”,如您所知,我无法访问 Module:: 中的 MVCEvent初始化方法。
【解决方案3】:

您是否在应用程序中使用ZfcBase? AbstractModule 有一个 boostrap 方法(not onBootstrap),由该事件处理程序在 init 方法中执行

$sharedManager->attach('Zend\Mvc\Application', 'bootstrap', function($e) use ($instance, $moduleManager) {
    $app = $e->getParam('application');
    ...
    $instance->bootstrap($moduleManager, $app);
});

当然你可以在没有 ZfcBase 的情况下使用这种方法。

那么就可以实现Zend\ServiceManager\ServiceLocatorAwareInterface:

public function bootstrap(\Zend\ModuleManager\ModuleManager $moduleManager, \Zend\Mvc\ApplicationInterface $app){
    $this->setServiceLocator($app->getServiceManager());
    parent::bootstrap($moduleManager, $app);
}

public function setServiceLocator(\Zend\ServiceManager\ServiceLocatorInterface $serviceLocator){
    $this->_serviceLocator = $serviceLocator;
    return $this;
}

public function getServiceLocator(){
    return $this->_serviceLocator;
}

【讨论】:

    【解决方案4】:

    也许会晚一点,但希望它会帮助其他人。在初始化点,服务管理器没有太多服务,但您可以访问它:

    public function init(ModuleManager $moduleManager)
    {
        $sm = $moduleManager->getEvent()->getParam('ServiceManager');
        $applicationConfig = $sm->get('applicationconfig');
        var_dump($applicationConfig['modules']);
    }
    

    在这种情况下,我们正在检索模块名称。

    【讨论】:

      【解决方案5】:

      这是个好主意。

      类模块

      public function onBootstrap(MvcEvent $e)
      {
      
          $sm = $app->getServiceManager();
          $config = $sm->get('config');
      

      这就是全部。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-26
        • 2013-05-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多