首页 文章

使用自定义Doctrine 2水化器进行依赖注入

提问于
浏览
5

我在Symfony 2项目中在Doctrine 2中设置了一个定制水合器,但是为了满足它的需要它需要另一个服务 . documentation for custom hydrators仅显示如何提供水合器类,因此无法注入依赖项 .

例如:

$em->getConfiguration()->addCustomHydrationMode('CustomHydrator', 'MyProject\Hydrators\CustomHydrator');

我怀疑Doctrine正在初始化水化器本身,因此任何依赖都需要首先通过其他一些Doctrine类 .

有没有办法提供一个定制的“水化工厂”或类似于Doctrine,这将允许注入额外的依赖项?没有这种能力,定制水合物似乎相当有限 .


Answer: 感谢Denis V.

我的工作原理如下 . 我无法发布实际代码,因此我将一些虚拟占位符放在一起,以便您可以看到它是如何组合在一起的 .

SRC /阿克米/ 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 /阿克米/ 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 /阿克米/ 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 */
    }
}

2 回答

  • 5

    尝试在config.yml中添加它

    doctrine:
        orm:
            hydrators:
                CustomHydrator: MyProject\Hydrators\CustomHydrator
    

    UPDATE

    由于您无法向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

    非常好的答案,但请注意,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>
    

相关问题