在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传递给映射器,但这对我来说似乎有很多重复的代码。
答案 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); }, . . . ), ); `
$model = $this->getServiceLocator()->get('MyModule\MyModel');
'service_manager' => array( 'factories' => array( 'MyModel' => 'MyModule\Models\MyModel', 'MyEntity' => 'MyModule\Entity\MyEntity', ), ),4.使用下面的服务管理器访问您的模型或类(例如,在控制器下)
$model = $this->getServiceLocator()->get('MyModel');德尔>