【问题标题】:Create a doctrine repository with dependencies (dependency injection) in ZF2在 ZF2 中创建具有依赖项(依赖注入)的学说存储库
【发布时间】:2015-11-10 13:16:12
【问题描述】:

我想创建一个具有硬依赖关系的存储库。我找到了 this blog post by Jurian Sluisman,但他建议从服务管理器获取存储库并在需要时将其注入到服务中。

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

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

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

【问题讨论】:

  • 您使用的是哪个容器? Symfony 容器直接处理这个问题。我怀疑您使用的是 ZF 容器?
  • @Cerad 是的,我正在使用 Zend Framework 2
  • 很好的问题。根据需要回答。谢谢

标签: php doctrine-orm dependency-injection zend-framework2 doctrine


【解决方案1】:

Doctrine 使用a factory class Doctrine\ORM\EntityManagerInterface\DefaultRepositoryFactory 来创建存储库实例。如果未设置自定义工厂,则在 the Doctrine\ORM\Configuration class 中创建此默认工厂 here in the getRepositoryFactory method

通过定义一个自定义的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'
        )
    )
)

【讨论】:

  • +1 我也是这样做的;我认为 Jurian 的博客文章是在 Doctrine 对实体管理器中默认存储库的创建进行硬编码时编写的。
  • 您在整个答案中都使用了“DefaultRepositoryFactory”,但随后在第 3 步中指定了“CustomRepositoryFactory”。这是复制/粘贴错误吗?或者有什么原因吗?假设您的意思是“默认”,我正在尝试继续进行操作,但是我遇到了一堆错误,并且不确定“自定义”的来源。谢谢!
  • 在@d.lanza38 他的评论之后更新(迟到总比不好)。
猜你喜欢
  • 1970-01-01
  • 2011-12-31
  • 2010-11-27
  • 1970-01-01
  • 2018-05-02
  • 2023-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多