zf2:如何在mapper中获取服务管理器

时间:2012-12-24 13:11:03

标签: zend-framework2

在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传递给映射器,但这对我来说似乎有很多重复的代码。

2 个答案:

答案 0 :(得分:8)

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

其次,有很多方法可以解决这个问题。在这个答案中,我将举例说明一种方法,仅提及另一种方法。

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

基本映射器类:

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;
    }
}

Mapper类:

namespace User\Mapper;

use User\Mapper\AbstractMapper;

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

由于在初始化程序运行时注入了服务管理器,因此应从服务管理器中检索映射程序。如果你不想/必须在mapper类中注入任何东西,那么一个invokable就足够了。可以在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_manager密钥中添加module_name/config/module.config.php密钥。您仍然需要添加一个创建数据库网关的工厂;以上只是一个例子。

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

答案 1 :(得分:2)

注意:正如Jurian Sluiman和andy124在他们的评论中指出的那样,从不注入服务管理器并依赖于域特定模型/对象内的服务管理器,这不是一个好习惯,因为这将使您的域特定对象僵硬和对便携性的影响。以下解决方案更具体针对提出的问题

我按照以下步骤在我的班级,模型等中获得sevicelocator(服务经理) <德尔> 1.创建实现ServiceMangerAwareInterface的类
2.在Module.php中定义serviceconfig中的条目 像这样

    public function getServiceConfig(){
    return array(
        'factories' => array(
                    /* Models */
            'MyModule\MyModel' =>  function($sm) {
                return new Models\MyModel($sm);
            },
                    /* Entities */
            'MyModule\MyEntity1' =>  function($sm) {
                return new Entity\MyEntity1($sm);
            },
            'MyModule\MyEntity2' =>  function($sm) {
                return new Entity\MyEntity2($sm);
            },
        .
        .
        .
        ),
    );
`
  1. 使用下面的服务管理器访问您的模型或类(例如,在控制器下)
    $model = $this->getServiceLocator()->get('MyModule\MyModel');
    
  2. <德尔> 您还可以在module.config.php中执行服务管理器配置     
        'service_manager' => array(
            'factories' => array(
                 'MyModel' => 'MyModule\Models\MyModel',
                 'MyEntity' => 'MyModule\Entity\MyEntity',
             ),
        ),
        
    4.使用下面的服务管理器访问您的模型或类(例如,在控制器下)     
        $model = $this->getServiceLocator()->get('MyModel');