Я создаю специальный гидратор в Doctrine 2 в проекте Symfony 2, но для того, чтобы он выполнял то, что ему нужно, ему нужна еще одна услуга. Документация для пользовательских гидраторов показывает только, как обеспечить класс гидратора, поэтому нет возможности вводить зависимости.
Например:
$em->getConfiguration()->addCustomHydrationMode('CustomHydrator', 'MyProject\Hydrators\CustomHydrator');
Я подозреваю, что Doctrine инициализирует сами гидраторы, и поэтому любые зависимости должны будут проходить через некоторые другие классы Doctrine.
Есть ли способ предоставить пользовательскую «фабрику гидратации» или аналогичную доктрине, которая позволила бы впрыскивать дополнительные зависимости? Пользовательские гидранты кажутся довольно ограниченными без этой возможности.
Ответ: Спасибо Денису 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 / Entity / 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 / Hydrator / 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 */ } }
Попробуйте добавить это в свой 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"] ]
На самом деле хороший ответ, но, пожалуйста, имейте в виду, что сторонники Doctrine явно заявили, что не продлевают 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>