3

我有两个示例,我想使用服务管理器获取服务并让它通过配置解决依赖关系,除了一个可变的依赖项/参数(伪代码,因为我意识到'get'只允许一个参数):

在控制器中,从数据库中获取实体:

$sm = $this->getServiceLocator();
$myObject = $sm->get('Model', $id);

在 mapper 中(服务管理器应该得到相应的适配器):

$sm = $this->getServiceLocator();
$tableGateway = $sm->get('TableGateway', $table);

实现这一目标的最佳做法是什么?

4

2 回答 2

1

您所描述的并不是 ServiceManager 设计的真正用例。就像它在罐头上所说的那样,它是一个管理服务的系统。用它来抓取单个实体并不合适。相反,使用 servicemanager 获取存储库,并使用该存储库获取实体:

$entity = $this->getServiceLocator()->get('FooRepository')->find($id);

在您的第二个示例中,您似乎拥有某种创建 TableGateways 的工厂。一个明智的做法是:

$gateway = $this->getServiceLocator()->get('TableGatewayFactory')->get($table);

或者,您可以为每个网关定义单独的服务:

$gateway = $this->getServiceLocator()->get('FooTableGateway');
于 2012-12-28T23:05:12.817 回答
1

据我所知,这不是直接可能的,但我在某处读到初始化器适用于这种类型的场景。

initializer 可以是任何实现 InitializerInterface 的类,它有一个方法 initialize(),initialize() 方法是用对象(模型的实例)和服务管理器实例调用的,你需要为每个对象编写条件需要初始化。构建初始化器类后,您需要在服务管理器配置(module.config.php)或 getServiceConfig() 方法中包含条目

虽然没有完全涵盖您的问题,但可能有助于朝着正确的方向前进

编辑

实现这一目标的最佳做法是什么?

回答这个问题

如果您的对象没有依赖项,您可以将其实现为

$myObject = new Model();
$myObject->find($id); which would initialize the model

如果您的模型具有依赖关系,并且如果您需要在开发阶段的后期将模型替换为其他对象,您可以将对象创建过程与服务定位器的服务工厂配置隔离开来,以实现这一点,在 getServicConfig() 方法中定义服务Module.php(您也可以定义自己的工厂代码并在配置中引用它,但在大多数用例中,简单的工厂定义就足够了)

public function getServiceConfig(){
    return array(
        'factories' => array(
            'Model' =>  function(ServiceLocatorInterface $sm) {
                return new Model($dependency1, $dependency2...);
            },
        ),
    );
}

然后模型访问代码将是

$myObject = $this->serviceLocator()->get('Model');
$myObject->find($id); which would initialize the model

最佳实践是定义一个接口,其中包括 find($id) 和所有其他需要调用的方法并在 Model 类中实现此接口,这样您就可以用实现该接口的任何其他对象替换您的工厂代码和您无需触摸 Model 对象的使用代码。

对于用例二,我假设您尝试重用或减少代码重复。如果你有一组有限的组合,你可以像下面这样实现

像这样定义服务工厂

public function getServiceConfig(){
    return array(
        'factories' => array(
            'Model/table1' =>  function(ServiceLocatorInterface $sm) {
                return new TableGateway('table1', $sm->get('db'));
            },
            'Model/table2' =>  function(ServiceLocatorInterface $sm) {
                return new TableGateway('table2', $sm->get('db'));
            },
        .
        .
        .
        .
        ),
    );
}    

访问 table1 作为

$tableGateway = $this->serviceLocator()->get('Model/table1');

注意:'Model/table1'是命名空间,避免覆盖配置,内部'/'将被服务管理器删除,名称将小写,注册和获取。

Zend\ServiceManager\ServiceManager 将它调用的内容存储canonicalNames在一个受保护的属性中。这是一个映射到规范名称的命名空间数组,这些命名空间是带有斜线并变为小写的命名空间。

于 2012-12-27T15:36:07.963 回答