我在Symfony 2项目中在Doctrine 2中设置了一个自定义水合器,但是为了满足它的需要它需要另一项服务。 documentation for custom hydrators仅显示如何提供水合器类,因此无法注入依赖项。
例如:
$em->getConfiguration()->addCustomHydrationMode('CustomHydrator', 'MyProject\Hydrators\CustomHydrator');
我怀疑Doctrine正在初始化水化器本身,因此任何依赖都需要首先通过其他一些Doctrine类。
有没有办法提供定制的水合工厂"或类似于允许注入其他依赖项的Doctrine?如果没有这种能力,定制水合器似乎相当有限。
答案:感谢Denis V
我的工作原理如下。我无法发布实际代码,因此我将一些虚拟占位符放在一起,以便您可以看到它是如何组合在一起的。
的src / Acme公司/ ExampleBundle /资源/配置/ services.yml
services:
doctrine.orm.entity_manager.abstract:
class: Acme\ExampleBundle\Entity\DoctrineEntityManager
factory_class: Acme\ExampleBundle\Entity\DoctrineEntityManager
factory_method: create
abstract: true
calls:
- [ setMyDependency, [@acme.my_custom_service]]
的src / Acme公司/ ExampleBundle /实体/ DoctrineEntityManager.php
namespace Acme\ExampleBundle\Entity;
use Acme\ExampleBundle\Hydrator\MyHydrator;
use Doctrine\Common\EventManager;
use Doctrine\DBAL\Connection;
use Doctrine\ORM\Configuration;
use Doctrine\ORM\EntityManager as BaseEntityManager;
use Doctrine\ORM\ORMException;
use Doctrine\ORM\Query;
class DoctrineEntityManager extends BaseEntityManager
{
protected $myDependency;
/**
* Note: This must be redefined as Doctrine's own entity manager has its own class name hardcoded in.
*/
public static function create($conn, Configuration $config, EventManager $eventManager = null)
{
if (!$config->getMetadataDriverImpl()) {
throw ORMException::missingMappingDriverImpl();
}
switch (true) {
case (is_array($conn)):
$conn = \Doctrine\DBAL\DriverManager::getConnection(
$conn, $config, ($eventManager ?: new EventManager())
);
break;
case ($conn instanceof Connection):
if ($eventManager !== null && $conn->getEventManager() !== $eventManager) {
throw ORMException::mismatchedEventManager();
}
break;
default:
throw new \InvalidArgumentException("Invalid argument: " . $conn);
}
return new self($conn, $config, $conn->getEventManager());
}
public function setMyDependency($myCustomService)
{
$this->myDependency = $myCustomService;
}
public function newHydrator($hydrationMode)
{
if ($hydrationMode == 'MyHydrationMode') {
return new MyHydrator($this, $this->myDependency);
}
return parent::newHydrator($hydrationMode);
}
}
的src / Acme公司/ ExampleBundle /保湿/ MyHydrator.php
namespace Acme\ExampleBundle\Hydrator;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Internal\Hydration\ObjectHydrator;
class MyHydrator extends ObjectHydrator
{
protected $myDependency;
public __construct(EntityManager $em, $myDependency)
{
parent::__construct($em);
$this->myDependency = $myDependency;
}
protected function hydrateAllData()
{
/* hydration stuff with my dependency here */
}
}
答案 0 :(得分:5)
尝试在config.yml中添加此内容
doctrine:
orm:
hydrators:
CustomHydrator: MyProject\Hydrators\CustomHydrator
<强>更新强>
由于您无法向Hydrator本身注入任何东西,您可以创建一个自定义的EntityManager(您自己建议)。
可以这样做:
services:
name_of_your_custom_manager:
class: %doctrine.orm.entity_manager.class%
factory_service: doctrine
factory_method: getManager
arguments: ["name_of_your_custom_manager"]
calls:
- [ setCustomDependency, ["@acme_bundle.custom_dependency"] ]
答案 1 :(得分:-1)
答案非常好,但请注意,Doctrine维护者明确表示not to extend Doctrine\ORM\EntityManager,我想他们将来会最终强制执行此事。
因此,在没有违反规则的情况下,提出的解决方案不是更清晰的解决方案:
<?php
declare(strict_types=1);
namespace App\Doctrine\ORM;
use Doctrine\Common\EventManager;
use Doctrine\DBAL\Connection;
use Doctrine\ORM\Configuration;
use Doctrine\ORM\Decorator\EntityManagerDecorator;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\ORMException;
class EntityManager extends EntityManagerDecorator
{
public function __construct(EntityManagerInterface $wrapped)
{
parent::__construct($wrapped);
}
public static function create($conn, Configuration $config, EventManager $eventManager = null)
{
if ( ! $config->getMetadataDriverImpl()) {
throw ORMException::missingMappingDriverImpl();
}
switch (true) {
case (is_array($conn)):
$conn = \Doctrine\DBAL\DriverManager::getConnection(
$conn, $config, ($eventManager ?: new EventManager())
);
break;
case ($conn instanceof Connection):
if ($eventManager !== null && $conn->getEventManager() !== $eventManager) {
throw ORMException::mismatchedEventManager();
}
break;
default:
throw new \InvalidArgumentException("Invalid argument: " . $conn);
}
return new EntityManager($conn, $config, $conn->getEventManager());
}
}
现在在services.xml文件中将此服务定义为装饰所需的实体管理器:
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<defaults autowire="true" autoconfigure="true" public="false" />
<service
id="decorated.doctrine.orm.default_entity_manager"
class="App\Doctrine\ORM\EntityManager"
decorates="doctrine.orm.default_entity_manager"
>
<argument type="service" id="decorated.doctrine.orm.default_entity_manager.inner" />
</service>
</services>
</container>