在ZF2中创建一个带有依赖项(依赖项注入)的条令存储库


Create a doctrine repository with dependencies (dependency injection) in ZF2

我想创建一个具有硬依赖关系的存储库。我发现了Jurian Sluisman的这篇博客文章,但他建议从服务经理那里获得存储库,并在需要的地方将其注入服务。

如果我能够使用getRepository方法从EntityManagerObjectManager实例中获得带有注入依赖项的自定义存储库,那会更好:

$objectManager->getRepository('My'Entity'Class');

如何在我的存储库中使用构造函数注入,并且仍然像往常一样通过getRepository方法直接从ObjectManager获取它们?

Doctrine使用工厂类Doctrine'ORM'EntityManagerInterface'DefaultRepositoryFactory来创建存储库实例。如果未设置自定义工厂,则在Doctrine'ORM'Configuration类的getRepositoryFactory方法中创建此默认工厂。

通过定义自定义repository_factory,我们可以覆盖这个默认的工厂类,并将自定义逻辑添加到将注入硬依赖项的工厂中:

为了说明如何做到这一点,我将展示一个示例,其中存储库工厂类通过构造函数注入创建依赖于ServiceLocator实例的存储库。

1)制作一个实现条令RepositoryFactory接口的自定义工厂类

这个类看起来与条令DefaultRepositoryFactory类非常相似。

<?php
namespace My'ORM'Repository;
use Doctrine'Common'Persistence'ObjectRepository;    
use Doctrine'ORM'Repository'RepositoryFactory;
use Doctrine'ORM'EntityManagerInterface;
use Zend'ServiceManager'ServiceLocatorAwareInterface;
use Zend'ServiceManager'ServiceLocatorAwareTrait;
use Zend'ServiceManager'ServiceLocatorInterface;
class CustomRepositoryFactory implements RepositoryFactory, ServiceLocatorAwareInterface
{
    use ServiceLocatorAwareTrait;
    /**
     * @var ObjectRepository[]
     */
    private $repositoryList = array();
    /**
     * @var ServiceLocator
     */
    protected $serviceLocator;
    /**
     * @param ServiceLocatorInterface $serviceLocator
     */
    public function __construct(ServiceLocatorInterface $serviceLocator)
    {
        $this->serviceLocator = $serviceLocator;
    }
    /**
     * {@inheritdoc}
     */
    public function getRepository(EntityManagerInterface $entityManager, $entityName)
    {
        $repositoryHash = $entityManager->getClassMetadata($entityName)->getName() . spl_object_hash($entityManager);
        if (isset($this->repositoryList[$repositoryHash])) {
            return $this->repositoryList[$repositoryHash];
        }
        return $this->repositoryList[$repositoryHash] = $this->createRepository($entityManager, $entityName);
    }
    /**
     * @param EntityManagerInterface $entityManager The EntityManager instance.
     * @param string                 $entityName    The name of the entity.
     * @return ObjectRepository
     */
    private function createRepository(EntityManagerInterface $entityManager, $entityName)
    {
        /* @var $metadata 'Doctrine'ORM'Mapping'ClassMetadata */
        $metadata            = $entityManager->getClassMetadata($entityName);
        $repositoryClassName = $metadata->customRepositoryClassName
            ?: $entityManager->getConfiguration()->getDefaultRepositoryClassName();
        // Constructor injection, I check with subclass of but it is just an example
        if(is_subclass_of($repositoryClassName, ServiceLocatorAwareInterface::class)){
            $serviceLocator = $this->getServiceLocator()
            $repository = new $repositoryClassName($entityManager, $metadata, $serviceLocator);
        }else{
            $repository = new $repositoryClassName($entityManager, $metadata);
        }
        return $repository;
    }
}

2)为存储库工厂创建一个工厂

<?php
namespace My'ORM'Repository'Factory;
use My'ORM'Repository'CustomRepositoryFactory;
use Zend'Cache'Storage'StorageInterface;
use Zend'ServiceManager'FactoryInterface;
use Zend'ServiceManager'ServiceLocatorInterface;
class CustomRepositoryFactoryFactory implements FactoryInterface
{
    /**
     * @param  ServiceLocatorInterface $serviceLocator
     * @return StorageInterface
     */
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        return new CustomRepositoryFactory($serviceLocator);
    }
}

3)在service_manager配置中为存储库工厂注册工厂

'service_manager' => array(
    'factories' => array(
        'My'ORM'Repository'CustomRepositoryFactory' => 'My'ORM'Repository'Factory'CustomRepositoryFactoryFactory'
    )
)

4)在条令配置中注册储存库工厂

'doctrine' => array(
    'configuration' => array(
        'orm_default' => array(
            'repository_factory' => 'My'ORM'Repository'CustomRepositoryFactory'
        )
    )
)