在 ZF2 中创建具有依赖项(依赖注入)的学说存储库
Create a doctrine repository with dependencies (dependency injection) in ZF2
我想制作一个具有硬依赖性的存储库。我找到了 this blog post by Jurian Sluisman 但他建议从服务管理器获取存储库并将其注入到需要的服务中。
如果我能够使用 getRepository
方法从我的 EntityManager
或 ObjectManager
实例中获取具有注入依赖项的自定义存储库,那就更好了:
$objectManager->getRepository('My\Entity\Class');
我如何在我的存储库中使用构造函数注入,并且仍然像通常一样直接使用 getRepository
方法从 ObjectManager
获取它们?
Doctrine 使用 a factory class Doctrine\ORM\EntityManagerInterface\DefaultRepositoryFactory
for creating repository instances. If no custom factory is set this default factory is created here in the getRepositoryFactory
method in the Doctrine\ORM\Configuration
class.
通过定义自定义 repository_factory
我们可以覆盖这个默认工厂 class 并将自定义逻辑添加到将注入硬依赖项的工厂:
为了说明如何执行此操作,我将展示一个示例,其中存储库工厂 class 通过构造函数注入创建依赖于 ServiceLocator
实例的存储库。
1) 创建一个自定义工厂 class 来实现学说 RepositoryFactory
接口
这个class看起来很像学说DefaultRepositoryFactory
class.
<?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
中为存储库工厂注册工厂
'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'
)
)
)
我想制作一个具有硬依赖性的存储库。我找到了 this blog post by Jurian Sluisman 但他建议从服务管理器获取存储库并将其注入到需要的服务中。
如果我能够使用 getRepository
方法从我的 EntityManager
或 ObjectManager
实例中获取具有注入依赖项的自定义存储库,那就更好了:
$objectManager->getRepository('My\Entity\Class');
我如何在我的存储库中使用构造函数注入,并且仍然像通常一样直接使用 getRepository
方法从 ObjectManager
获取它们?
Doctrine 使用 a factory class Doctrine\ORM\EntityManagerInterface\DefaultRepositoryFactory
for creating repository instances. If no custom factory is set this default factory is created here in the getRepositoryFactory
method in the Doctrine\ORM\Configuration
class.
通过定义自定义 repository_factory
我们可以覆盖这个默认工厂 class 并将自定义逻辑添加到将注入硬依赖项的工厂:
为了说明如何执行此操作,我将展示一个示例,其中存储库工厂 class 通过构造函数注入创建依赖于 ServiceLocator
实例的存储库。
1) 创建一个自定义工厂 class 来实现学说 RepositoryFactory
接口
这个class看起来很像学说DefaultRepositoryFactory
class.
<?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
'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'
)
)
)