0

如何将服务管理器注入 Doctrine 存储库以允许我检索 Doctrine 实体管理器?

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

http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/tutorials/getting-started.html

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

我的 Doctrine 存储库如下所示:

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();

编辑:附加链接表明我可能需要将类转换为服务,
https://stackoverflow.com/a/13508799/1325365

但是,如果这是最好的路线,那么我将如何让我的 Doctrine Entity 了解该服务。目前,我在 doc 块中包含一个指向该类的注释。

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

2 回答 2

6

我处理事情的方式是这样的:

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

public function getServiceConfig()
{
    return array(
        'factories' => array(
            'my-service-entityname' => 'My\Factory\EntitynameServiceFactory',
        )
    );
}

接下来是创建工厂类src\My\Factory\EntitynameServiceFactory.php。这是您将 EntityManager 注入 Entity-Services 的部分(而不是注入实体本身,实体根本不需要这种依赖关系)

这个类看起来像这样:

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

接下来是创建src\My\Service\EntitynameService.php。这实际上是您创建所有 getter 函数和东西的部分。我个人从全局DoctrineEntityService扩展这些服务,现在我将首先为您提供EntitynameService的代码。所有这一切都是为了获得正确的存储库!

<?php
namespace My\Service;

class EntitynameService extends DoctrineEntityService
{
    public function getEntityRepository()
    {
        if (null === $this->entityRepository) {
            $this->setEntityRepository($this->getEntityManager()->getRepository('My\Entity\Entityname'));
        }
        return $this->entityRepository;
    }
}

到这里为止的这一部分应该很容易理解(我希望),但这还不是很有趣。魔术正在全球DoctrineEntityService发生。这就是代码!

<?php
namespace My\Service;

use Zend\EventManager\EventManagerAwareInterface;
use Zend\EventManager\EventManagerInterface;
use Zend\ServiceManager\ServiceManagerAwareInterface;
use Zend\ServiceManager\ServiceManager;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityRepository;

class DoctrineEntityService implements
    ServiceManagerAwareInterface,
    EventManagerAwareInterface
{
    protected $serviceManager;
    protected $eventManager;
    protected $entityManager;
    protected $entityRepository;


    /**
     * Returns all Entities
     *
     * @return EntityRepository
     */
    public function findAll()
    {
        $this->getEventManager()->trigger(__FUNCTION__ . '.pre', $this, array('entities' => $entities));
        $entities = $this->getEntityRepository()->findAll();
        $this->getEventManager()->trigger(__FUNCTION__ . '.post', $this, array('entities' => $entities));
        return $entities;
    }

    public function find($id) {
        return $this->getEntityRepository()->find($id);
    }

    public function findByQuery(\Closure $query)
    {
        $queryBuilder = $this->getEntityRepository()->createQueryBuilder('entity');
        $currentQuery = call_user_func($query, $queryBuilder);
       // \Zend\Debug\Debug::dump($currentQuery->getQuery());
        return $currentQuery->getQuery()->getResult();
    }

    /**
     * Persists and Entity into the Repository
     *
     * @param Entity $entity
     * @return Entity
     */
    public function persist($entity)
    {
        $this->getEventManager()->trigger(__FUNCTION__ . '.pre', $this, array('entity'=>$entity));
        $this->getEntityManager()->persist($entity);
        $this->getEntityManager()->flush();
        $this->getEventManager()->trigger(__FUNCTION__ . '.post', $this, array('entity'=>$entity));

        return $entity;
    }

    /**
     * @param \Doctrine\ORM\EntityRepository $entityRepository
     * @return \Haushaltportal\Service\DoctrineEntityService
     */
    public function setEntityRepository(EntityRepository $entityRepository)
    {
        $this->entityRepository = $entityRepository;
        return $this;
    }

    /**
     * @param EntityManager $entityManager
     * @return \Haushaltportal\Service\DoctrineEntityService
     */
    public function setEntityManager(EntityManager $entityManager)
    {
        $this->entityManager = $entityManager;
        return $this;
    }

    /**
     * @return EntityManager
     */
    public function getEntityManager()
    {
        return $this->entityManager;
    }

    /**
     * Inject an EventManager instance
     *
     * @param  EventManagerInterface $eventManager
     * @return \Haushaltportal\Service\DoctrineEntityService
     */
    public function setEventManager(EventManagerInterface $eventManager)
    {
        $this->eventManager = $eventManager;
        return $this;
    }

    /**
     * Retrieve the event manager
     * Lazy-loads an EventManager instance if none registered.
     *
     * @return EventManagerInterface
     */
    public function getEventManager()
    {
        return $this->eventManager;
    }

    /**
     * Set service manager
     *
     * @param ServiceManager $serviceManager
     * @return \Haushaltportal\Service\DoctrineEntityService
     */
    public function setServiceManager(ServiceManager $serviceManager)
    {
        $this->serviceManager = $serviceManager;
        return $this;
    }

    /**
     * Get service manager
     *
     * @return ServiceManager
     */
    public function getServiceManager()
    {
        return $this->serviceManager;
    }
}

那么这有什么作用呢?这个DoctrineEntityService几乎是您在全球范围内所需要的(根据我目前的经验)。它有fincAll(),find($id)findByQuery($closure)

您的下一个问题(希望如此)只会是“现在如何从我的控制器中使用它?”。就像调用您在第一步中设置的服务一样简单!假设您的控制器中有此代码

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

该函数findByQuery()需要一个闭包。($queryBuilder或者您可以选择如何命名该变量)将是\Doctrine\DBAL\Query\QueryBuilder. 不过,这将永远联系在一起ONE Repository!因此entity.somekey,这entity.将是您当前正在使用的任何存储库。

如果您需要访问,EntityManager您要么只实例化,DoctrineEntityService要么调用$entityService->getEntityManager()并从那里继续。

我不知道这种方法是否过于复杂或其他什么。在设置新的 Entity/EntityRepository 时,您需要做的就是添加一个新的工厂和一个新的服务。这两个几乎都是复制粘贴,每个类中都有两行代码更改。

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

于 2012-12-31T15:31:17.700 回答
6

只要您扩展 Doctrine\ORM\EntityRepository,您就可以通过调用EntityRepository::getEntityManager()$_em属性立即访问实体管理器。从 Doctrine\ORM\EntityRepository 类的继承允许您这样做。

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

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、服务管理器)到持久层(Doctrine)。我的持久性(实体、存储库...)层不应该引用网络前端,也不应该知道它的存在。如果我的系统在某种程度上做相反的事情,那么可能我做错了什么。

年末快乐

于 2012-12-31T17:45:59.120 回答