Service 注入服务管理器以在ZF2中构建条令存储库

Service 注入服务管理器以在ZF2中构建条令存储库,service,dependency-injection,doctrine,zend-framework2,Service,Dependency Injection,Doctrine,Zend Framework2,如何将服务管理器注入到条令存储库中,以允许检索条令实体管理器 我正在使用ZF2 Commons DoctrineORMModule,并正在尝试实现下面链接中的Doctrine教程底部列出的存储库示例: 但是,我一直收到一条致命错误消息:在C:\zendProject\zf2中的非对象上调用成员函数get,这表明我没有服务定位器的工作实例 我的条令存储库如下所示: namespace Calendar\Repository; use Doctrine\ORM\EntityRepository,

如何将服务管理器注入到条令存储库中,以允许检索条令实体管理器

我正在使用ZF2 Commons DoctrineORMModule,并正在尝试实现下面链接中的Doctrine教程底部列出的存储库示例:

但是,我一直收到一条致命错误消息:在C:\zendProject\zf2中的非对象上调用成员函数get,这表明我没有服务定位器的工作实例

我的条令存储库如下所示:

namespace Calendar\Repository;

use  Doctrine\ORM\EntityRepository,
     Calendar\Entity\Appointment,
     Calendar\Entity\Diary;

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

class ApptRepository extends EntityRepository implements ServiceLocatorAwareInterface 
{
   protected $services;

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

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

  public function getUserApptsByDate()
  {
     $dql = "SELECT a FROM Appointment a";

     $em = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');

     $query = $em()->createQuery($dql);

     return $query->getResult();
   }
}
然后,我想使用以下模式在控制器中调用此函数:

$diary = $em->getRepository('Calendar\Entity\Appointment')->getUserApptsByDate();
编辑:附加的链接建议我可能需要将类转换为服务,

然而,如果这是最好的途径,那么我将如何使我的条令实体意识到服务。目前,我在doc块中包含了一个指向该类的注释

@ORM\Entity (repositoryClass="Calendar\Repository\ApptRepository") 

我处理事情的方式是:

首先,我为每个实体注册一个服务。这是在Module.php中完成的

下一步是创建工厂类src\My\factory\EntitynameServiceFactory.php。这是将EntityManager注入实体服务的部分,而不是实体本身,实体根本不需要这种依赖关系

这个类看起来像这样:

<?php
namespace My\Factory;

use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\ServiceManager\FactoryInterface;
use My\Service\EntitynameService;

class EntitynameServiceFactory implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        $service = new EntitynameService();
        $service->setEntityManager($serviceLocator->get('Doctrine\ORM\EntityManager'));
        return $service;
    }
}
public function getUserApptsByDate()
{
    $dql = "SELECT a FROM Appointment a";
    $em = $this->getEntityManager();// Or $em=$this->_em;
    $query = $em()->createQuery($dql);
    return $query->getResult();
}
函数findByQuery需要一个闭包。$queryBuilder或您希望如何命名该变量,您可以选择它将是\doctor\DBAL\Query\queryBuilder的一个实例。但这将始终绑定到一个存储库!因此,entity.somekey就是实体。将是您当前使用的任何存储库

如果您需要访问EntityManager,您可以只实例化DoctrineEntityService,或者调用$entityService->getEntityManager并从那里继续

我不知道这种方法是否过于复杂。设置新实体/实体存储库时,只需添加新工厂和新服务。这两个类几乎都是复制粘贴,每个类中有两行代码更改


我希望这已经回答了您的问题,并让您了解了如何组织与ZF2的工作。

只要您扩展了条令\ORM\EntityRepository,您就可以通过调用EntityRepository::getEntityManager或$\u em属性立即访问实体管理器。从条令\ORM\EntityRepository类继承允许您这样做

您的方法现在应该如下所示:

<?php
namespace My\Factory;

use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\ServiceManager\FactoryInterface;
use My\Service\EntitynameService;

class EntitynameServiceFactory implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        $service = new EntitynameService();
        $service->setEntityManager($serviceLocator->get('Doctrine\ORM\EntityManager'));
        return $service;
    }
}
public function getUserApptsByDate()
{
    $dql = "SELECT a FROM Appointment a";
    $em = $this->getEntityManager();// Or $em=$this->_em;
    $query = $em()->createQuery($dql);
    return $query->getResult();
}
我始终牢记,对数据的访问应该从web前端Zend MVC、服务管理器到持久性层。我的持久性实体、存储库。。。层不应该引用web前端,或者不知道它的存在。如果我的系统在某种程度上做了相反的事情,那么我可能做错了什么


新年快乐

Sam-这需要一点时间才能完成,但这是一个非常好的答案-非常感谢。一个问题是,eventManager触发器调用在DoctrineTityService persist方法中做了什么?这些事件是否可以用来触发其他动作?你用它们干什么?遗憾的是我甚至不能回答这个问题。嗯,我可以,他们用一个没有附加任何动作的名称触发一个事件。所以基本上什么也没发生。这是复制粘贴留下的。。。您可能会将CacheHandler附加到这些事件或其他内容。如果我没有弄错的话,我想这在ZF2s快速入门教程的某个地方有介绍。这个答案似乎有些过分了。没有必要有一个医生资格服务或任何这些东西。只需从zf2服务管理器获取条令EntityManager,或将其注入工厂并使用“$EntityManager->getRepository'MyEntity”。更简单、更快,这就是原则的使用方式。@superdweebie该服务所做的一切就是提供全局功能,如findAll、persist等。当然,您可以从EntityManager本身完成这一切,但我认为将一些基本功能封装在一个基类中是一件好事。此外,该entityService只编写一次。正如上面的代码示例所示,所有的子实体都只是几行。@sam我理解您试图做什么,但这不是教义的本意。很久以前,我为DoctrineMongoODMModule申请了一个类似的东西,后来被温和地拒绝了,并解释了这些东西。条令本身可以提供对方法的更直接的访问,如在存储库上查找,但它并不是为了促进良好的关注点分离和清晰的体系结构,所以很清楚哪些代码做什么。调用->getRepository并不困难,也不会像您的解决方案那样混淆规则。感谢这是一个非常简单的解决方案。我没有考虑过直接访问$em。我已经选择了将这组DB调用作为一项服务,因为这些调用将在许多模块中使用。我
我还在玩代码,但这应该允许我使用标准条令代码格式简化代码。@yechabbi的+1。我想补充一下,您可以在第54行看到entityManager作为$em。
public function someAction()
{
    /** @var $entityService \my\Service\EntitynameService */
    $entityService = $this->getServiceLocator()->get('my-service-entityname');

    // A query that finds all stuff
    $allEntities = $entityService->findAll();

    // A query that finds an ID 
    $idEntity = $entityService->find(1);

    // A query that finds entities based on a Query
    $queryEntity = $entityService->findByQuery(function($queryBuilder){
        /** @var $queryBuilder\Doctrine\DBAL\Query\QueryBuilder */
        return $queryBuilder->orderBy('entity.somekey', 'ASC'); 
    });
}
public function getUserApptsByDate()
{
    $dql = "SELECT a FROM Appointment a";
    $em = $this->getEntityManager();// Or $em=$this->_em;
    $query = $em()->createQuery($dql);
    return $query->getResult();
}