php - 在 ZF2 中创建具有依赖项(依赖注入(inject))的 Doctrine 存储库

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

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

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

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

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

最佳答案

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

通过定义一个自定义的repository_factory,我们可以覆盖这个默认的工厂类并向工厂添加自定义逻辑来注入(inject)硬依赖:

为了说明如何执行此操作,我将展示一个示例,其中存储库工厂类通过构造函数注入(inject)创建依赖于 ServiceLocator 实例的存储库。

1) 创建一个自定义工厂类来实现 RepositoryFactory 接口(interface)

这个类看起来与 Doctrine 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 config

中为repository factory注册工厂
'service_manager' => array(
    'factories' => array(
        'My\ORM\Repository\CustomRepositoryFactory' => 'My\ORM\Repository\Factory\CustomRepositoryFactoryFactory'
    )
)

4)在doctrine config中注册repository factory

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

关于php - 在 ZF2 中创建具有依赖项(依赖注入(inject))的 Doctrine 存储库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33630909/

相关文章:

php - 如何在while条件下比较两个数组

php - TinyMCE 更改语言

php - 我的 HTML 表单使用 PHP 和 MySQL 无法正常工作

php - 使用通配符排除 laravel 路由

php - 选择连接表原则 2 中的列

orm - 如何在 Doctrine 2 中丢弃对实体的未刷新更改?

php - JMS 序列化程序无法序列化 : cannot access private property

php - 我应该在我的 php 项目中使用依赖注入(inject)吗?

c# - 如何通过依赖注入(inject)将有状态服务放入组合根中而没有可怕的副作用?

java - 一个接口(interface)多种实现。如何在运行时获得正确的