Doctrine orm Zend框架2+;条令:在模型中获取实体管理器

Doctrine orm Zend框架2+;条令:在模型中获取实体管理器,doctrine-orm,zend-framework2,Doctrine Orm,Zend Framework2,编辑1:看来我没有很好地解释自己。Foo类不是实体。只是一个通用模型,我希望能够访问实体管理器 编辑2:我认为我的问题没有答案。基本上,我想要一个可以访问EntityManager的类,而不需要服务管理器调用这个类,这仅仅是因为它可能被服务管理器也不调用的类调用。换句话说,我试图实现Zend_Registry在ZF1中实现的功能。我必须找到另一种方法来做我想做的事 我尝试在模型中访问Doctrine的实体管理器,方式与在控制器中的方式类似: $this->getServiceLocator

编辑1:看来我没有很好地解释自己。Foo类不是实体。只是一个通用模型,我希望能够访问实体管理器

编辑2:我认为我的问题没有答案。基本上,我想要一个可以访问EntityManager的类,而不需要服务管理器调用这个类,这仅仅是因为它可能被服务管理器也不调用的类调用。换句话说,我试图实现Zend_Registry在ZF1中实现的功能。我必须找到另一种方法来做我想做的事

我尝试在模型中访问Doctrine的实体管理器,方式与在控制器中的方式类似:

$this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
$foo = $this->getServiceLocator()->get('MyModule\Model\Foo');
$foo->test();
ZF2手册(http://framework.zend.com/manual/2.0/en/modules/zend.service-manager.quick-start.html)说:

默认情况下,Zend Framework MVC注册一个初始值设定项,该初始值设定项将ServiceManager实例(Zend\ServiceManager\ServiceLocatorInterface的实现)注入任何实现Zend\ServiceManager\ServiceLocatorAwareInterface的类中

因此,我在以下类中创建了一个:

<?php
namespace MyModule\Model;

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

class Foo implements ServiceLocatorAwareInterface
{
    protected $services;

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

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

    public function test()
    {
        $em = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
    }
}   
这会引发以下错误:

PHP致命错误:对非对象调用成员函数get()

所以,我想我在什么地方遗漏了什么,但是什么呢?哪里怎么用?也许有更容易访问实体管理器的方法


谢谢

从您的问题中,我发现您主要有两个误解,一个是关于您的设计策略(在您的模型上注入EntityManager),另一个是关于如何使用服务管理器(ServiceLocatorAwareInterface)。在我的回答中,我会尽量集中在第二个问题上

初始值设定项是php闭包,在服务管理器将其返回给您之前,会对从服务管理器访问的每个实例调用这些闭包

以下是初始值设定项的示例:

// Line 146 - 150 of Zend\Mvc\Service\ServiceManagerConfig class + comments

$serviceManager->addInitializer(function ($instance) use ($serviceManager) {
        if ($instance instanceof ServiceManagerAwareInterface) {
            $instance->setServiceManager($serviceManager);
        }
    });
正如您所看到的,每次要求Service Manager返回实现ServiceManagerWareInterface接口的实例/对象时,它都会设置/向其中注入Service Manager实例

顺便说一下,在以前的代码中,由于没有定义
setServiceManager
方法,您忽略了正确实现接口。然而,这不是你唯一的问题。 首先,如果您希望服务管理器将自身注入到您的模型中,那么您需要通过工厂从它调用/构造模型实例(在此过程中,它将调用初始值设定项),例如,如果您的类具有复杂的依赖项

[编辑]

例如:

在MyModule中

namespace MyModule;
use Zend\ModuleManager\Feature\ServiceProviderInterface;
use MyModule\Model\Foo;

class Module implements ServiceProviderInterface{

//Previous code

public function getServiceConfig()
{
    return array(
        'instances' => array(
            'myModelClass'        => new Foo(),
            ),
       );

}
现在,当您需要一个Foo实例时,您应该调用服务管理器:

$serviceManager->get('myModelClass')


不要忘记定义
setServiceManager
方法,否则您将无法正确实现ServiceManagerWareInterface

我认为,您唯一缺少的是将模型类添加到可调用的列表中,并通过服务管理器检索它

因此,基本上要将其添加到module.conf.php中:

并像这样实例化模型对象(如果在控制器中):


您不应在条令实体内使用实体管理器。条令2实体只是表上操作的数据存储。您可能希望查看具有实体管理器访问权限的自定义存储库类。如果您提供一个示例,说明您希望在实体内部使用实体管理器做什么,我可能会帮助您找到正确的方法。对于您的问题,只有当您使用服务定位器/DI获取实体时,它才应该被初始化。我建议您不要在任何类中手动检索EM,因为这将给您创建单元测试的时间。此外,如果将来更改服务别名(doctor.entitymanager.orm_default),则需要重构所有内容。顺便说一句,您正在使用
new
关键字创建实例。ZF2只能在使用ServiceManager和/或Di时注入依赖项。啊,是的,还有单元测试。但在实体内部设置实体经理甚至是最糟糕的设计Daniel M。条令团队不鼓励这样做,因为这与条令的设计模式背道而驰。实体只是一个数据存储——不是更多,不是更少。关于这个问题的第一个答案是:我认为这个问题描述得非常好。谁说过实体中的实体管理器?如果不清楚的话,这个问题是关于从通用类访问实体管理器的。你关于不使用新关键字的评论至少给了我进一步调查的方向。谢谢,但我很抱歉,你的答案是:1。我知道我遗漏了什么,但如果我知道了什么,我就不需要问了。2.为什么实体经理会知道我的模型,即使知道,它对我有什么帮助?这里我不是说实体类,而是说驻留在\module\MyModule\src\MyModule\Model下的模型。很抱歉,您的问题对于“模型”类的用法不够清楚。然而,您对实现
ServiceLocatorAwareInterface
的理解确实是错误的。我将编辑我的答案,以说明如何实现您的需求谢谢,我非常感谢您的努力。我想这让我明白了一件事。从某种意义上说,我认为服务管理器就是Zend_Registry在ZF1中的功能,在这里您可以设置一些内容,然后从任何需要的地方访问它。我意识到我错了。我想我必须更具创造性。嗯,ZF2的情况完全不同。然而,在某种意义上,服务管理器实际上可以用来“放置某些东西”并从任何地方访问它。它没有访问服务的“静态”方法,也不像Zend_注册表那样是一个单例。向Service Manager声明服务通常是通过实现ServiceProvi的模块类来完成的
return array(
    'service_manager' => array(
        'invokables' => array(
            'MyModule\Model\Foo' => 'MyModule\Model\Foo',
        ),
    ),
);
$foo = $this->getServiceLocator()->get('MyModule\Model\Foo');
$foo->test();