Zend framework2 多控制器的单一工厂?

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

简言之,我的问题是:我可以将一个工厂用于多个控制器吗

更多详情:

我在/config/autoload/global.php中有一些全局非模块特定设置,如下所示:

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')
确实解决了这个问题!最后我在所有控制器中都设置了我的设置!感谢你非常有用的支持!