在 ZF2 中注入 Service Manager 以构建 Doctrine 存储库 [英] Injecting the Service Manager to Build a Doctrine Repository in ZF2

查看:13
本文介绍了在 ZF2 中注入 Service Manager 以构建 Doctrine 存储库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

How do I inject the service manager into a Doctrine repository to allow me to retrieve the Doctrine Entity Manager?

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

I using the ZF2-Commons DoctrineORMModule and are trying to implement the repository example listed in the Doctrine Tutorial (bottom of tutorial in link below):

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

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

However, I keep getting a message "Fatal error: Call to a member function get() on a non-object in C:zendProjectzf2 ... ", which suggests that I do not have a working instance of the service locator.

我的 Doctrine 存储库如下所示:

My Doctrine repository looks like this:

namespace CalendarRepository;

use  DoctrineORMEntityRepository,
     CalendarEntityAppointment,
     CalendarEntityDiary;

use ZendServiceManagerServiceLocatorAwareInterface;
use ZendServiceManagerServiceLocatorInterface;

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

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

     return $query->getResult();
   }
}

然后我想在我的控制器中使用以下模式调用它:

I then want to call this in my controller using the following pattern:

$diary = $em->getRepository('CalendarEntityAppointment')->getUserApptsByDate();

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

The attached link suggests that I may need to convert the class to a service,
https://stackoverflow.com/a/13508799/1325365

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

However, if this is the best route, how would I then make my Doctrine Entity aware of the service. At the moment I include an annotation in the doc block pointing to the class.

@ORMEntity (repositoryClass="CalendarRepositoryApptRepository") 

推荐答案

我做事的方式是这样的:

The way i approach things is this:

首先我为每个实体注册一个服务.这是在 Module.php

First i register a Service for each entity. This is done inside Module.php

public function getServiceConfig()
{
    return array(
        'factories' => array(
            'my-service-entityname' => 'MyFactoryEntitynameServiceFactory',
        )
    );
}

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

Next thing would be to create the factory class srcMyFactoryEntitynameServiceFactory.php. This is the part where you inject the EntityManager into your Entity-Services (not into the entity itself, the entity doesn't need this dependency at all)

这个类看起来像这样:

<?php
namespace MyFactory;

use ZendServiceManagerServiceLocatorInterface;
use ZendServiceManagerFactoryInterface;
use MyServiceEntitynameService;

class EntitynameServiceFactory implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        $service = new EntitynameService();
        $service->setEntityManager($serviceLocator->get('DoctrineORMEntityManager'));
        return $service;
    }
}

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

Next thing in line is to create the srcMyServiceEntitynameService.php. And this is actually the part where you create all the getter functions and stuff. Personally i extend these Services from a global DoctrineEntityService i will first give you the code for the EntitynameService now. All this does is to actually get the correct repository!

<?php
namespace MyService;

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

到这里为止的这部分应该很容易理解(我希望),但这还不是很有趣.神奇的事情发生在全局 DoctrineEntityService.这就是它的代码!

This part until here should be quite easy to understand (i hope), but that's not all too interesting yet. The magic is happening at the global DoctrineEntityService. And this is the code for that!

<?php
namespace MyService;

use ZendEventManagerEventManagerAwareInterface;
use ZendEventManagerEventManagerInterface;
use ZendServiceManagerServiceManagerAwareInterface;
use ZendServiceManagerServiceManager;
use DoctrineORMEntityManager;
use DoctrineORMEntityRepository;

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);
       // endDebugDebug::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 DoctrineORMEntityRepository $entityRepository
     * @return HaushaltportalServiceDoctrineEntityService
     */
    public function setEntityRepository(EntityRepository $entityRepository)
    {
        $this->entityRepository = $entityRepository;
        return $this;
    }

    /**
     * @param EntityManager $entityManager
     * @return HaushaltportalServiceDoctrineEntityService
     */
    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 HaushaltportalServiceDoctrineEntityService
     */
    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 HaushaltportalServiceDoctrineEntityService
     */
    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)

So what does this do? This DoctrineEntityService pretty much is all what you globally need (to my current experience). It has the fincAll(), find($id) and the findByQuery($closure)

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

Your next question (hopefully) would only be "How to use this from my controller now?". It's as simple as to call your Service, that you have set up in the first step! Assume this code in your Controllers

public function someAction()
{
    /** @var $entityService myServiceEntitynameService */
    $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 $queryBuilderDoctrineDBALQueryQueryBuilder */
        return $queryBuilder->orderBy('entity.somekey', 'ASC'); 
    });
}

函数 findByQuery() 需要一个闭包.$queryBuilder(或者您可以选择如何命名该变量)将是 DoctrineDBALQueryQueryBuilder 的一个实例.不过,这将始终与 ONE Repository 相关联!因此 entity.somekey entity. 将是您当前正在使用的任何存储库.

The function findByQuery() would expect an closure. The $queryBuilder (or however you want to name that variable, you can choose) will be an instance of DoctrineDBALQueryQueryBuilder. This will always be tied to ONE Repository though! Therefore entity.somekey the entity. will be whatever repository you are currently working with.

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

If you need access to the EntityManager you'd either only instantiate only the DoctrineEntityService or call the $entityService->getEntityManager() and continue from there.

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

I don't know if this approach is overly complex or something. When setting up a new Entity/EntityRepository, all you need to do is to add a new Factory and a new Service. Both of those are pretty much copy paste with two line change of code in each class.

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

I hope this has answered your question and given you some insight of how work with ZF2 can be organized.

这篇关于在 ZF2 中注入 Service Manager 以构建 Doctrine 存储库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆