我的问题简而言之:我可以为多个控制器使用单个工厂吗?
更多详情:
我在 /config/autoload/global.php 中有一些全局非模块特定设置,如下所示:
return array(
'settings' => array(
'setting_a' => 'foo',
'setting_b' => 'bar'
),
// More ZF default configuration ...
);
现在我希望在每个控制器中都可以访问这些设置,而无需一直致电$this->getServiceLocator()->get('config')
。
所以我的想法是在我的$settings
中引入一个类属性AbstractController
,它将注入配置数组。我试图直接在AbstractController
的构造函数中获取配置。但是getServiceLocator()
当时似乎没有准备好并返回NULL。
我可以为每个控制器构建Controller Factories并注入如下设置:
class ControllerFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator) {
$config = $serviceLocator->get('config');
return new \MyModule\Controller\MyController($config['settings']);
}
}
但它会一遍又一遍地相同。所以我的问题是:我可以为多个控制器使用一个工厂吗?
在我的 module.config.php 中,我可以为多个控制器指定一个工厂类:
return array(
'controllers' => array(
'factories' => array(
'MyModule\Controller\MyControllerA' => 'MyModule\Factory\ControllerFactory',
'MyModule\Controller\MyControllerB' => 'MyModule\Factory\ControllerFactory',
'MyModule\Controller\MyControllerC' => 'MyModule\Factory\ControllerFactory',
)
),
);
但是在工厂中我需要手工返回实际的Controller对象(参见上面的例子),当然这只适用于每个Controller一个工厂。
希望,我明白了问题。
更新2013-03-24:
虽然我首先通过创建初始化程序来遵循建议的解决方案,但我从未真正喜欢将其用于注入配置。
所以我一直在挖掘并最终创建一个Controller插件来接收设置。
插件的代码如下所示:
use Zend\Mvc\Controller\Plugin\AbstractPlugin;
class Settings extends AbstractPlugin
{
protected $settings;
public function __invoke()
{
$config = $this->getController()->getServiceLocator()->get('Config');
if (isset($config['settings']) && is_array($config['settings'])) {
$this->settings = $config['settings'];
}
return $this->settings;
}
}
使用
在 module.config.php 中添加插件后'controller_plugins' => array(
'invokables' => array(
'settings' => 'My\Controller\Plugin\Settings',
)
),
只需拨打$this->settings()
,即可轻松访问控制器中的设置。希望这对任何人都有帮助。
答案 0 :(得分:6)
您可以尝试附加初始化程序,然后在创建控制器时,根据已知的初始化程序检查实例。如果实例匹配给定的接口或抽象类,那么您可以应用一些通用逻辑。
我没有用控制器测试这种方法,但鉴于ControllerLoader是一种ServiceManager / ServiceLocator,理论上应该可以工作。
'controllers' => array (
'initializers' => array(
'MyApplication\Controller\Initializer'
)
),
然后Initalizer看起来像:
class Initializer implements InitializerInterface
{
public function initialize($instance, ServiceLocatorInterface $serviceLocator)
{
if (!$instance instanceof MyControllerInterface)
{
return;
}
// Do something for this instance
}
}
答案 1 :(得分:1)
不确定您今后如何更新“更新2013-03-24”;)
为什么不像你建议的那样使用控制器,而是将你想要的代码放在一个抽象工厂中,然后从中继承,例如:
abstract class AbstractControllerFactory implements FactoryInterface
{
protected function initialise(ServiceLocatorInterface $serviceLocator, $controller) {
$config = $serviceLocator->get('config');
$controller->setConfig($config);
}
}
class ControllerFactory extends AbstractControllerFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator) {
$controller = new \MyModule\Controller\MyController();
$this->initialise($serviceLocator, $controller);
return $controller;
}
}
答案 2 :(得分:1)
甚至更干净:将您的控制器作为invokables添加到配置中,然后执行类似这样的操作,将您的控制器转换为单行:
abstract class AbstractControllerFactory implements FactoryInterface
{
protected $controllerKey;
public function createService(ServiceLocatorInterface $serviceLocator) {
$config = $serviceLocator->get('config');
$controller = $serviceLocator->get($this->controllerKey);
$controller->setConfig($config);
return $controller;
}
}
class ControllerFactory extends AbstractControllerFactory implements FactoryInterface
{
protected $controllerKey = 'mymodule_controller_mycontroller';
}