Zend framework2 zf2:如何在mapper中获取服务管理器
在Zend Framework 1中,我有几个映射器,它们从父映射器类继承了setDbTable和getDbTable 现在在ZF2 a中,我面临一个问题,即我需要模型中的服务管理器,而我不知道如何获得它:Zend framework2 zf2:如何在mapper中获取服务管理器,zend-framework2,Zend Framework2,在Zend Framework 1中,我有几个映射器,它们从父映射器类继承了setDbTable和getDbTable 现在在ZF2 a中,我面临一个问题,即我需要模型中的服务管理器,而我不知道如何获得它: class Mapper { protected $tableGateway; protected $module = 'application'; public function setTableGateway($table
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
给出一个致命错误:
Call to undefined method Application\Model\Mapper\Doc::getServiceLocator()
如何在我的模型中获得服务经理?还是我没有按ZF2的方式做事?我知道如何在我的控制器中获取服务管理器,并将tableGateway传递给映射器,但这对我来说似乎是代码的大量重复。注意:正如Jurian Sluiman和andy124在他们的评论中指出的,永远不要在特定于域的模型/对象中注入服务管理器和依赖服务管理器,这不是一个好的实践,因为这会使特定于领域的对象变得僵硬,并影响可移植性。下面的解决方案更具体地针对所提出的问题 $model = $this->getServiceLocator()->get('MyModel'); 我按照以下步骤在我的类、模型等中获取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); }, . . . ), ); ` 公共函数getServiceConfig(){ 返回数组( “工厂”=>数组( /*模型*/ “MyModule\MyModel”=>函数($sm){ 返回新模型\MyModel($sm); }, /*实体*/ 'MyModule\MyEntity1'=>函数($sm){ 返回新实体\MyEntity1($sm); }, 'MyModule\MyEntity2'=>函数($sm){ 返回新实体\MyEntity2($sm); }, . . . ), ); `
首先,我认为您的意思是希望从mapper类而不是模型访问服务管理器。我将避免使用后者。有关更多详细信息,请参阅我对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');
}
}
映射器类:
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\u manager
键下>module_name/config/module.config.php
。或者,它可以在module类“getServiceConfig
方法中配置。但是,您的映射器类现在或将来很可能会有一些依赖项,因此您可能希望使用工厂来代替。这样,您可以让服务管理器注入一个表gat进入mapper类的途径
'service_manager' => array(
'factories' => array(
'MyModel' => 'MyModule\Models\MyModel',
'MyEntity' => 'MyModule\Entity\MyEntity',
),
),
// 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);
},
),
);
可以在模块的module.php
文件中的getServiceConfig
方法中添加上述内容,或者在service\u manager
中的factories
键中添加module\u name/config/module.config.php
。您仍然需要添加一个创建数据库网关的工厂;以上只是一个例子例如
'service_manager' => array(
'factories' => array(
'MyModel' => 'MyModule\Models\MyModel',
'MyEntity' => 'MyModule\Entity\MyEntity',
),
),
这就是我要做的。当然,可以简单地在mapper类中为服务管理器提供一个getter和setter方法,并从控制器访问这些方法(控制器有一个
getServiceLocator
方法)然后像那样注入。不过,我自己不会采用这种方法。在模型中注入服务管理器通常是一个非常糟糕的主意。尝试在类中注入依赖项,而不是依赖于要注入的服务容器。这是“依赖项注入”与“服务容器”Jurian Sluiman:这对我来说是一个困难的讨论,因为我最近才了解依赖注入,但我想我已经了解了基本的想法。下面Andy的答案如何(我接受了,因为它是有效的)?在您看来,这也是一种反模式吗?您可以好好阅读本文:(对我来说,Anthony Ferrara是一位非常受尊敬的开发人员)。这并不是真的那么黑/白,但关于同一件事,这里提出了一个类似的问题:您的答案中有一些错误:1.如果您有自己的工厂,并且已经在其中注入了SM,则不需要实现ServiceManagerWareInterface
。2.一般来说,在域模型中注入SM的想法是非常复杂的在你的config.php
(你可能指的是module.config.php
)中,你使用模型作为一个可调用的服务,但你使用工厂服务。由于这些原因,我投你反对票,但你可以在
'service_manager' => array(
'factories' => array(
'MyModel' => 'MyModule\Models\MyModel',
'MyEntity' => 'MyModule\Entity\MyEntity',
),
),
$model = $this->getServiceLocator()->get('MyModel');