6

在 Zend Framework 1 中,我有几个映射器,它们从父 Mapper 类继承了 setDbTable 和 getDbTable。

现在在 ZF2 中,我面临一个问题,即我需要模型中的服务管理器,但我不知道如何获得它:

    class Mapper
    {
        protected $tableGateway;
        protected $module = 'application';

        public function setTableGateway($table)
            {
                if (is_string($table)) {
                    $class = $this->module . '\Model\DbTable\\' . ucfirst($table);
                    $sm = $this->getServiceLocator(); <= Fatal error: Call to undefined method Mapper::getServiceLocator()
                    $tableGateway = (class_exists($class)) ? $sm->get($class) : $sm->get(new TableGateway($table));
                } else {
                    $tableGateway = $table;
                }

                if (!$tableGateway instanceof Zend\Db\TableGateway\AbstractTableGateway) {
                    throw new \Exception('Invalid table data gateway provided');
                }
                $this->tableGateway = $tableGateway;
                return $this;
            }

        // more code

该行:

$sm = $this->getServiceLocator();

给出一个致命错误:

Call to undefined method Application\Model\Mapper\Doc::getServiceLocator()

如何在我的模型中获取服务管理器?还是我不是按照 ZF2 的方式做事?我知道如何在我的控制器中获取服务管理器并将 tableGateway 传递给映射器,但这对我来说似乎有很多重复的代码。

4

2 回答 2

8

首先,我认为您的意思是要从映射器类而不是模型访问服务管理器。我会避免做后者。有关更多详细信息,请参阅我对 Raj 回答的评论。

其次,有很多方法可以解决这个问题。在这个答案中,我将为您提供一种方法的示例,并仅提及另一种方法。

查看服务管理器的文档(向下滚动一点),它声明默认初始值设定项已添加为默认值。此初始化程序检查从服务管理器检索的对象是否实现了Zend\ServiceManager\ServiceLocatorAwareInterface. 如果是,则将服务管理器注入到对象中。因此,如果您只是在映射器类中实现接口,这可能会自动发生。您可以使用抽象基类来避免为每个映射器类重写它。也许像下面这样。

基本映射器类:

namespace User\Mapper;

use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class AbstractMapper implements ServiceLocatorAwareInterface {
    protected $service_manager;

    public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
    {
        $this->service_manager = $serviceLocator;
    }

    public function getServiceLocator()
    {
        return $this->service_manager;
    }
}

映射器类:

namespace User\Mapper;

use User\Mapper\AbstractMapper;

class UserMapper extends AbstractMapper {
    public function doSomething() {
        $sm = $this->getServiceLocator();
        $sm->get('something');
    }
}

由于服务管理器是在初始化程序运行时注入的,因此应该从服务管理器中检索映射器。如果您不想/必须将任何东西注入您的映射器类,那么一个可调用的就足够了。它们可以添加到键下invokables,该键嵌套在 中的service_manager键下module_name/config/module.config.php。或者,可以在模块类的getServiceConfig方法中配置。但是,您的映射器类现在或将来很可能会有一些依赖项,因此您可能希望使用工厂来代替。这样,您可以让服务管理器将表网关注入映射器类。

// Remember to include the appropriate namespaces
return array(
    'factories' => array(
        'User\Mapper\UserMapper' => function($service_manager) {
            $table_gateway = $service_manager->get('User\Model\DbTable\UserGateway');
            return new UserMapper($table_gateway);
        },
    ),
);

以上内容可以添加getServiceConfig到模块Module.php文件中的方法中 -或者factories在. 您仍然需要添加一个创建数据库网关的工厂;以上只是一个例子。service_managermodule_name/config/module.config.php

这就是我将如何去做。当然,可以简单地在映射器类中为服务管理器提供一个 getter 和 setter 方法,然后从控制器访问它们(控制器有一个getServiceLocator方法)并像这样注入它。不过,我自己不会采用这种方法。

于 2012-12-26T15:33:30.540 回答
2

注意:正如 Jurian Sluiman 和 andy124 在他们的评论中指出的那样,永远不要在特定领域的模型/对象中注入服务管理器并依赖服务管理器,这不是一个好的做法,因为这会使特定领域的对象变得僵化并影响可移植性。下面的解决方案更具体到所问的问题

我按照以下步骤在我的班级、模型等中获取服务定位器(服务管理器)
1.创建实现ServiceMangerAwareInterface的类
2. 像这样在 Module.php 中定义 serviceconfig 中的条目

    公共函数 getServiceConfig(){
    返回数组(
        '工厂' => 数组(
                    /* 楷模 */
            'MyModule\MyModel' => 函数($sm){
                返回新模型\MyModel($sm);
            },
                    /* 实体 */
            'MyModule\MyEntity1' => 函数($sm){
                返回新实体\MyEntity1($sm);
            },
            'MyModule\MyEntity2' => 函数($sm){
                返回新实体\MyEntity2($sm);
            },
        .
        .
        .
        ),
    );
`
  1. 使用如下服务管理器访问您的模型或类(例如在控制器下)
    $model = $this->getServiceLocator()->get('MyModule\MyModel');
    
您还可以在 module.config.php 中进行服务管理器配置
    'service_manager' => 数组(
        '工厂' => 数组(
             'MyModel' => 'MyModule\Models\MyModel',
             'MyEntity' => 'MyModule\Entity\MyEntity',
         ),
    ),
    
4. 使用如下服务管理器访问您的模型或类(例如在控制器下)
    $model = $this->getServiceLocator()->get('MyModel');
    
于 2012-12-24T15:56:34.743 回答