Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
691 views
in Technique[技术] by (71.8m points)

php - Dependency injection with custom Doctrine 2 hydrator

I'm setting up a custom hydrator in Doctrine 2 in a Symfony 2 project, but for it to do what it needs it requires another service. The documentation for custom hydrators only shows how to provide a hydrator class, so there's no way to inject dependencies.

For example:

$em->getConfiguration()->addCustomHydrationMode('CustomHydrator', 'MyProjectHydratorsCustomHydrator');

I suspect Doctrine is initialising the hydrators itself and as such any dependencies would need to be passed through some other Doctrine classes first.

Is there a way to provide a custom "hydration factory" or similar to Doctrine that would allow injection of additional dependencies? Custom hydrators seem fairly limited without this capability.


Answer: Thanks to Denis V

I got this working as follows. I can't post the actual code so I've put together some dummy placeholders so you can see how it fits together.

src/Acme/ExampleBundle/resources/config/services.yml

services:
    doctrine.orm.entity_manager.abstract:
        class:          AcmeExampleBundleEntityDoctrineEntityManager
        factory_class:  AcmeExampleBundleEntityDoctrineEntityManager
        factory_method: create
        abstract:       true
        calls:
            - [ setMyDependency, [@acme.my_custom_service]]

src/Acme/ExampleBundle/Entity/DoctrineEntityManager.php

namespace AcmeExampleBundleEntity;

use AcmeExampleBundleHydratorMyHydrator;
use DoctrineCommonEventManager;
use DoctrineDBALConnection;
use DoctrineORMConfiguration;
use DoctrineORMEntityManager as BaseEntityManager;
use DoctrineORMORMException;
use DoctrineORMQuery;

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 = DoctrineDBALDriverManager::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 AcmeExampleBundleHydrator;

use DoctrineORMEntityManager;
use DoctrineORMInternalHydrationObjectHydrator;

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 */
    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Try adding this in your config.yml

doctrine:
    orm:
        hydrators:
            CustomHydrator: MyProjectHydratorsCustomHydrator

UPDATE

As you cannot inject anything to the Hydrator itself, you can instead create a custom EntityManager (that you suggested yourself).

It can be done this way:

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"] ]

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...