ZF2:将特定于动作的配置注入控制器


ZF2: Injecting action-specific configuration into controller

至少有三种方法——Zend''Di、ConfigAwareInterface和ControllerFactory——我考虑过将配置注入控制器。

或多或少的官方建议是ControllerFactory,它导致了以下代码(或者,如果你喜欢闭包,也可以是此代码——我不喜欢,因为它们更难测试):

// module.config.php
'controllers' => array (
    'factories' => array (
        'Module'Concept'Index' => 'Concept'ControllerFactory'IndexControllerFactory',
    ),
),
'some_config_key' => array (
    'x' => 'foo'
),
// src/Concept/ControllerFactory/IndexControllerFactory.php
class IndexControllerFactory implements FactoryInterface {
    public function createService(ServiceLocatorInterface $serviceLocator) {
        $config = $serviceLocator->getServiceLocator()->get('config');
        $controller = new 'Html'Controller'IndexController($config['some_config_key']);
        return $controller;
    }
}
// src/Concept/Controller/IndexController.php
class IndexController {
    public function __construct($config) {
        // here we go, yay!  we have $config['x'] == 'foo'
    }
}

如果每个操作需要不同的配置(例如,一个操作可能需要DB,另一个操作则可能需要贝宝),那么当操作只需要部分控制器配置时,传递所有的控制器配置似乎是不合适的。

那么,对于哪些动作需要哪些配置的知识应该进入工厂还是进入控制器?也就是说,工厂应该根据手头的行动只给控制器它需要的东西,还是应该给控制器所有的配置并在内部解决它?

更新
特定于操作的依赖关系就是:特定的。控制器声明它需要什么,然后以任何必要的方式使用它。这两种行动有着根本不同的需求,这表明控制器的范围可能太广,可能是分离的候选者。

但不管怎样,最好的方法——清晰、稳健,显然符合ZF未来的方向——是在服务工厂制造所需的服务,然后制造具有必要服务的控制器。

两个工厂:服务和控制器。控制器与它必须拥有的服务声明其__construct合同,然后工厂根据需要从模块配置中制造这些服务。

这个问题主要是基于观点的,所以你可以得到很多不同的答案。

这两种方法都很好,因为:

  • 正如您所知,我们在ZF2中看到的是服务管理器,所有合并的配置都在所有应用程序中运行。因此,即使这不是最好的方法,它也被广泛使用
  • 如果我们考虑到依赖反转原则(事实上,我们已经考虑到了),以及高内聚性和低耦合性原则,这些原则告诉我们隔离是好的,所有组件都不必对其他组件了解太多,并且模块内的一切都应该是强相关的,我们可以认为,在每个控制器中都有所有合并的配置,甚至让控制器知道关联合并配置数组中的哪个键包含其配置,这可能不是最好的事情,模块应该接收的可能是其配置,无论它来自更大的数组、工厂、地狱还是其他地方,因为事实上,它不需要知道这一点,这无关紧要

因此,最好的方法可能是只注入它所期望的配置。事实上,这就是我们在创建ViewHelper时要做的事情,通常我们不会注入所有内容,只注入我们需要的内容。

这可能会让人困惑,因为有时你可能还需要一些其他的通用配置,而不仅仅是与模块相关的配置,在这种情况下,你必须考虑它。但在大多数情况下,更优雅的解决方案可能是注入你需要的东西。

作为进一步的重要论点,我在sam minds博客中读到

仍然有几件事只是不理想。一个小例子是,很多人使用$this->getServiceLocator()。虽然这是可以的,这实际上被认为是不好的做法。事情的样子现在,这个特性将在Zend Framework 3(ZF3)中被删除基本上强制人们使用ServiceManager。

因此,我们可以认为,正确的方法是尽可能地进行依赖注入,并尽可能少地让每个组件知道。