注入服务管理器以在ZF2中构建一个原则存储库 [英] Injecting the Service Manager to Build a Doctrine Repository in ZF2

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

问题描述



我使用ZF2-Commons DoctrineORMModule,并试图将服务管理器注入到Doctrine存储库中,以允许我检索Doctrine实体管理器实施教义教程中列出的存储库示例(下面链接教程的底部):



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



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



我的Doctrine存储库如下所示:

 命名空间Calendar\库; 

使用Doctrine\ORM\EntityRepository,
Calendar\Entity\Appointment,
Calendar\Entity\Diary;

使用Zend\ServiceManager\ServiceLocatorAwareInterface;
使用Zend\ServiceManager\ServiceLocatorInterface;

class ApptRepository扩展EntityRepository实现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实体知道这个服务。目前,我在指向该类的doc块中包含一个注释。

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


解决方案

我的方法是这样的:



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

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

);
}

接下来的事情将是创建工厂类 src\My \Factory\EntitynameServiceFactory.php 即可。这是您将EntityManager注入实体服务的部分(不是实体本身,实体根本不需要此依赖)



此类看起来如下所示:

 <?php 
命名空间My\Factory;

使用Zend\ServiceManager\ServiceLocatorInterface;
使用Zend\ServiceManager\FactoryInterface;
使用My\Service\EntitynameService;

class EntitynameServiceFactory实现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 
命名空间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 
命名空间My\Service;

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

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


/ **
*返回所有实体
*
* @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();
}

/ **
*存储库中的持久性和实体
*
* @param实体$实体
* @return实体
* /
public function persist($ entity)
{
$ this-> getEventManager() - > trigger(__ FUNCTION__。'.pre',$ this,array ( '实体'=> $实体));
$ 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 $这 - > EntityManager的;
}

/ **
*注入EventManager实例
*
* @param EventManagerInterface $ eventManager
* @return \Haushaltportal \Service\DoctrineEntityService
* /
public function setEventManager(EventManagerInterface $ eventManager)
{
$ this-> eventManager = $ eventManager;
return $ this;
}

/ **
*检索事件管理器
*如果没有注册,Lazy加载一个EventManager实例。
*
* @return EventManagerInterface
* /
public function getEventManager()
{
return $ this-> eventManager;
}

/ **
*设置服务管理器
*
* @param ServiceManager $ serviceManager
* @return \Haushaltportal\\ \\ Service \DoctrineEntityService
* /
public function setServiceManager(ServiceManager $ serviceManager)
{
$ this-> serviceManager = $ serviceManager;
return $ this;
}

/ **
*获取服务管理器
*
* @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');

//查找所有内容的查询
$ allEntities = $ entityService-> findAll();

//找到一个ID
$ idEntity = $ entityService-> find(1)的查询;

//根据查询查找实体的查询
$ 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 实体。将是您正在使用的任何存储库。



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



我不知道这种做法过于复杂或者是什么。当设置新的Entity / EntityRepository时,您需要做的就是添加一个新的Factory和一个新的Service。这两个都是在每个类中都有两行代码的复制粘贴。



我希望这回答了你的问题,并给出了一些关于如何使用ZF2可以组织。


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

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

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

My Doctrine repository looks like this:

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

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

$diary = $em->getRepository('Calendar\Entity\Appointment')->getUserApptsByDate();

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

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.

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

解决方案

The way i approach things is this:

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

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

Next thing would be to create the factory class src\My\Factory\EntitynameServiceFactory.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)

This class looks something like this:

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

Next thing in line is to create the src\My\Service\EntitynameService.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 My\Service;

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

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

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)

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

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 \Doctrine\DBAL\Query\QueryBuilder. This will always be tied to ONE Repository though! Therefore entity.somekey the entity. will be whatever repository you are currently working with.

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

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.

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

这篇关于注入服务管理器以在ZF2中构建一个原则存储库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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