Gre*_*bes 0 service doctrine dependency-injection zend-framework2
如何将服务管理器注入Doctrine存储库以允许我检索Doctrine Entity Manager?
我使用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();
}
}
Run Code Online (Sandbox Code Playgroud)
然后,我想使用以下模式在我的控制器中调用它:
$diary = $em->getRepository('Calendar\Entity\Appointment')->getUserApptsByDate();
Run Code Online (Sandbox Code Playgroud)
编辑:附加的链接表明我可能需要将类转换为服务,
/sf/answers/945615961/
但是,如果这是最佳路线,那么我将如何让我的Doctrine Entity了解该服务.目前,我在指向该类的doc块中包含一个注释.
@ORM\Entity (repositoryClass="Calendar\Repository\ApptRepository")
Run Code Online (Sandbox Code Playgroud)
我处理事情的方式是这样的:
首先,我为每个实体注册一个服务.这是在Module.php中完成的
public function getServiceConfig()
{
return array(
'factories' => array(
'my-service-entityname' => 'My\Factory\EntitynameServiceFactory',
)
);
}
Run Code Online (Sandbox Code Playgroud)
接下来是创建工厂类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;
}
}
Run Code Online (Sandbox Code Playgroud)
接下来要做的就是创建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;
}
}
Run Code Online (Sandbox Code Playgroud)
这部分直到这里应该很容易理解(我希望),但这并不是太有趣.神奇的事情发生在全球的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;
}
}
Run Code Online (Sandbox Code Playgroud)
那这是做什么的呢?这个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');
});
}
Run Code Online (Sandbox Code Playgroud)
该函数findByQuery()预计将关闭.该$queryBuilder(或不过你要来命名变量,你可以选择)将是一个实例\Doctrine\DBAL\Query\QueryBuilder.这总是与之相关ONE Repository!因此entity.somekey,entity.它将是您当前使用的任何存储库.
如果您需要访问,EntityManager您只需要实例化DoctrineEntityService或调用,$entityService->getEntityManager()然后从那里继续.
我不知道这种方法是否过于复杂或类似.设置新的Entity/EntityRepository时,您需要做的就是添加一个新的Factory和一个新的Service.这两个都是复制粘贴,每个类中有两行代码更改.
我希望这已经回答了你的问题,并让你了解如何组织ZF2的工作.
只要扩展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();
}
Run Code Online (Sandbox Code Playgroud)
我始终记住,访问我的数据应该从Web前端(Zend MVC,Service Manager)到持久层(Doctrine).我的持久性(实体,存储库......)层不应该引用Web前端,也不应该知道它存在.如果我的系统在某种程度上做反向,那么我可能做错了.
年底快乐