简而言之我的问题:我可以为多个控制器使用单个工厂吗?
更多细节:
我在/config/autoload/global.php中有一些全局非模块特定设置,如下所示:
return array(
'settings' => array(
'setting_a' => 'foo',
'setting_b' => 'bar'
),
// More ZF default configuration ...
);
Run Code Online (Sandbox Code Playgroud)
现在,我希望在每个控制器中都可以访问这些设置,而无需一直打电话$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']);
}
}
Run Code Online (Sandbox Code Playgroud)
但它会一遍又一遍地相同.所以我的问题是:我可以为多个控制器使用单个工厂吗?
在我的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',
)
),
);
Run Code Online (Sandbox Code Playgroud)
但是在工厂中我需要手动返回实际的Controller对象(参见上面的例子),当然这只适用于每个Controller一个Factory.
希望,我明白我的问题.
更新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;
}
}
Run Code Online (Sandbox Code Playgroud)
添加插件中后module.config.php与
'controller_plugins' => array(
'invokables' => array(
'settings' => 'My\Controller\Plugin\Settings',
)
),
Run Code Online (Sandbox Code Playgroud)
我可以通过简单地调用轻松访问控制器中的设置$this->settings().希望这有助于任何人.
作为创建控制器实例对已知检查初始化你可以尝试连接的初始化,然后.如果实例匹配给定的接口或抽象类,那么您可以应用一些通用逻辑.
我没有测试与控制器的这种做法,但考虑到ControllerLoader是一种在理论工作的ServiceManager /服务定位它应该的.
'controllers' => array (
'initializers' => array(
'MyApplication\Controller\Initializer'
)
),
Run Code Online (Sandbox Code Playgroud)
然后Initalizer看起来像:
class Initializer implements InitializerInterface
{
public function initialize($instance, ServiceLocatorInterface $serviceLocator)
{
if (!$instance instanceof MyControllerInterface)
{
return;
}
// Do something for this instance
}
}
Run Code Online (Sandbox Code Playgroud)