Zend Framework 2 - Controller通过(修改?)Factory

时间:2016-04-28 11:46:42

标签: zend-framework2 dependencies factory instantiation strategy-pattern

我有一个抽象服务类SAbstract,由ConcreteServiceAConcreteServiceB继承。现在我在我的控制器的工厂类中实例化ConcreteServiceA并在我的控制器中注入服务。

在我的控制器中的特定操作中,我想与ConcreteServiceA交换ConcreteServiceB以更改行为。因为它们具有相同的接口(抽象类SAbstract),所以我也可以将它注入到我的控制器中(服务是策略模式)。

但我不想直接在我的控制器中实例化ConcreteServiceB以保持我的代码清洁(以便轻松重构和交换行为)。

一个可能的解决方案是为我的控制器创建第二个工厂,它注入ConcreteServiceB而不是ConcreteServiceA,但后来我复制了许多不好的代码...... 另一个解决方案是在我的控制器中注入两个服务(但是这"闻起来像#34;就像坏代码一样)。

这是a delegator factory正确的方法吗?然后我必须在我的控制器中实现setter ...

有更好的方法吗?

我试图用示意图来形象化我的阶级关系。

AbstractService <|--<inherit>- ConcreteServiceA
AbstractService <|--<inherit>- ConcreteServiceB
Controller -<use>--> AbstractService
Controller:ActionA -<use>--> ConcreteServiceA:exportAction()
Controller:ActionB -<use>--> ConcreteServiceB:exportAction()

1 个答案:

答案 0 :(得分:3)

  

在我的控制器中的特定操作中,我想与ConcreteServiceB交换ConcreteServiceA以更改行为。因为它们具有相同的界面。

您可以为每个操作配置路由以使用不同的控制器服务名称;然后配置控制器工厂以使用配置注入所需的服务。

路线配置可能如下所示。

'router' => [
    'routes' => [
        'foo' => [
            'type' => 'literal',
            'options' => [
                'route' => '/foo',
                'defaults' => [
                    'controller' => 'MyControllerWithFooService',
                    'action' => 'actionThatNeedsFooService',
                ],
            ],
        ],
        'bar' => [
            'type' => 'literal',
            'options' => [
                'route' => '/bar',
                'defaults' => [
                    'controller' => 'MyControllerWithBarService',
                    'action' => 'actionThatNeedsBarService',
                ],
            ],
        ],
    ],
]

然后添加服务和控制器的配置。

'app_config' => [
    'MyControllerWithFooService' => [
        'service_name' => 'FooService',
    ],
    'MyControllerWithFooService' => [
        'service_name' => 'BarService',
    ],
],
'service_manager' => [
    'factories' => [
        'FooService' => 'FooServiceFactory'
        'BarService' => 'BarServiceFactory'
    ],
],
'controllers' => [
    'factories' => [
        'MyControllerWithFooService' => 'MyControllerServiceFactory'
        'MyControllerWithBarService' => 'MyControllerServiceFactory'
    ],
]

MyControllerServiceFactory可能非常简单。

class MyControllerServiceFactory
{
    public function __invoke($controllerManager, $name, $requestedName)
    {
        $sm = $controllerManager->getServiceLocator();

        $config = $sm->get('config');

        if (empty($config['app_config'][$requestedName])) {
            throw new ServiceNotCreatedException('No config set!');
        }

        $serviceName = $config['app_config'][$requestedName]['service_name'];
        $service = $sm->get($serviceName);

        return new MyController($service);
    } 
}