Zend framework2 多控制器的单一工厂?
简言之,我的问题是:我可以将一个工厂用于多个控制器吗 更多详情: 我在/config/autoload/global.php中有一些全局非模块特定设置,如下所示:Zend framework2 多控制器的单一工厂?,zend-framework2,Zend Framework2,简言之,我的问题是:我可以将一个工厂用于多个控制器吗 更多详情: 我在/config/autoload/global.php中有一些全局非模块特定设置,如下所示: return array( 'settings' => array( 'setting_a' => 'foo', 'setting_b' => 'bar' ), // More ZF default configuration ... ); class Co
return array(
'settings' => array(
'setting_a' => 'foo',
'setting_b' => 'bar'
),
// More ZF default configuration ...
);
class ControllerFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator) {
$config = $serviceLocator->get('config');
return new \MyModule\Controller\MyController($config['settings']);
}
}
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;
}
}
现在我想让这些设置在每个控制器中都可以访问,而不必一直调用$this->getServiceLocator()->get('config')
因此,我的想法是在我的AbstractController
中引入一个class属性$settings
,它与配置数组一起注入。我试图直接在AbstractController
的构造函数中获取配置。但是,getServiceLocator()
当时似乎没有准备好,返回NULL
我可以为每个控制器构建控制器工厂,并注入如下设置:
return array(
'settings' => array(
'setting_a' => 'foo',
'setting_b' => 'bar'
),
// More ZF default configuration ...
);
class ControllerFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator) {
$config = $serviceLocator->get('config');
return new \MyModule\Controller\MyController($config['settings']);
}
}
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中,我可以为多个控制器指定一个工厂类:
return array(
'controllers' => array(
'factories' => array(
'MyModule\Controller\MyControllerA' => 'MyModule\Factory\ControllerFactory',
'MyModule\Controller\MyControllerB' => 'MyModule\Factory\ControllerFactory',
'MyModule\Controller\MyControllerC' => 'MyModule\Factory\ControllerFactory',
)
),
);
但是在工厂中,我需要手动返回实际的控制器对象(参见上面的示例),这当然只适用于每个控制器一个工厂
希望,我把我的问题说清楚了
更新2013-03-24:
虽然我首先按照建议的解决方案创建了一个初始值设定项,但我从未真正喜欢将其用于配置的注入
所以我一直在挖掘,最终创建了一个控制器插件来接收设置
插件的代码如下所示:
return array(
'settings' => array(
'setting_a' => 'foo',
'setting_b' => 'bar'
),
// More ZF default configuration ...
);
class ControllerFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator) {
$config = $serviceLocator->get('config');
return new \MyModule\Controller\MyController($config['settings']);
}
}
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中添加插件后
只要调用
$this->settings()
,我就可以轻松访问控制器中的设置。希望这对任何人都有帮助。您可以尝试附加一个初始值设定项,然后在创建控制器时,根据已知的初始值设定项检查实例。如果实例与给定接口或抽象类匹配,则可以应用一些公共逻辑
我没有用控制器测试过这种方法,但考虑到ControllerLoader是一种ServiceManager/ServiceLocator类型,理论上它应该可以工作
'controllers' => array (
'initializers' => array(
'MyApplication\Controller\Initializer'
)
),
然后初始化器看起来像:
class Initializer implements InitializerInterface
{
public function initialize($instance, ServiceLocatorInterface $serviceLocator)
{
if (!$instance instanceof MyControllerInterface)
{
return;
}
// Do something for this instance
}
}
不确定您将来如何更新“更新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;
}
}
或者更干净:将控制器作为可调用项添加到配置中,然后执行类似操作,将控制器变成一行程序:
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';
}
谢谢你的主意。初始值设定项本身的工作方式与您描述的相同,但是,一旦我将其添加到“控制器”数组中,控制器映射不知何故会丢失,并且会出现一个错误,即“请求的控制器无法映射到现有的控制器类”。看起来“控制器”中的“可调用”和“初始值设定项”相互咬合。你有什么建议吗?我会回到刚才的invokables,然后应用初始值设定项,如果初始值设定项得到一个实例,那么进行调试。引发错误消息的原因可能有很多,请确保所有使用定义都正确并且没有错误。为了更深入地挖掘,我还将查看\Zend\Mvc\Service\ControllerLoaderFactory.php,并将其一直跟踪到\Zend\Mvc\Controller\ControllerManager.php–我希望这会有所帮助。找到原因:引发服务未找到异常的是初始化器::initialize()中的
$serviceLocator->get('Config')
调用。因此,配置在初始化阶段似乎还没有准备好。我仍然无法将我的设置放入控制器:-(现在将尝试一种解决方法。首先尝试$serviceLocator上的var_dump(启用xdebug)应该会提示您在该点可以提取什么。还可以尝试$serviceLocator->getServiceLocator()->get('Config'))因为可能插件ServiceManager不是主要的。DrBeza,你是最好的!$serviceLocator->getServiceLocator()->get('Config')
确实解决了这个问题!最后我在所有控制器中都设置了我的设置!感谢你非常有用的支持!