有没有办法在Symfony2中指定Doctrine2 Entitymanager实现类?

时间:2011-11-15 15:41:37

标签: configuration symfony doctrine-orm

我目前正在使用Symfony2和Doctrine2,但我必须覆盖Doctrine2 EntityManager并添加一些“取消删除”功能(内部的ACL)。

所以我想知道:有没有办法覆盖EntityManager类并在Symfony2中指定Doctrine2以将其用作EntityManager的实现?

感谢您的帮助!

4 个答案:

答案 0 :(得分:20)

在Doctrine 2.4(Doctrine 2.4 release)之后你需要使用装饰器。不要直接扩展EntityManager。 首先,您需要实现自己的实体管理器装饰器,扩展Doctrine \ ORM \ Decorator \ EntityManagerDecorator(如@Dana) 但是你不能只将doctrine.orm.entity_manager.class更改为你的新装饰器,因为EntityManagerDecorator在它的构造函数中需要EntityManagerInterface:

public function __construct(EntityManagerInterface $wrapped)

你不能只将doctrine.orm.entity_manager作为参数传递给它,因为它将是一个递归。 不要这样做:

return new self(\Doctrine\ORM\EntityManager::create(

您需要的是在装饰器等服务中配置装饰器:

yourcompany_entity_manager:
    public: false
    class: YourCompany\ORM\EntityManagerDecorator
    decorates: doctrine.orm.default_entity_manager
    arguments: ["@yourcompany_entity_manager.inner"]

现在,您将把装饰器作为Doctrine的默认实体管理器。 @ yourcompany_entity_manager.inner 实际上是 doctrine.orm.default_entity_manager 的链接,该链接将传递给 yourcompany_entity_manager 构造函数。

用于配置装饰器的Symfony文档:link

顺便说一句,这个命令对于调试你的服务非常有用:

  

app / console container:debug | grep entity_manager

答案 1 :(得分:7)

是的,可以通过两个步骤完成:

1 - 覆盖doctrine.orm.entity_manager.class参数以指向您的自定义实体管理器(应扩展Doctrine\ORM\EntityManager。)

2 - 您的自定义实体管理器必须覆盖create方法,以便它返回您的类的实例。请参阅下面的示例,并注意有关MyEntityManager的最后一行:

public static function create($conn, Configuration $config, EventManager $eventManager = null) {
        if (!$config->getMetadataDriverImpl()) {
            throw ORMException::missingMappingDriverImpl();
        }

        if (is_array($conn)) {
            $conn = \Doctrine\DBAL\DriverManager::getConnection($conn, $config, ($eventManager ? : new EventManager()));
        } else if ($conn instanceof Connection) {
            if ($eventManager !== null && $conn->getEventManager() !== $eventManager) {
                throw ORMException::mismatchedEventManager();
            }
        } else {
            throw new \InvalidArgumentException("Invalid argument: " . $conn);
        }

        // This is where you return an instance of your custom class!
        return new MyEntityManager($conn, $config, $conn->getEventManager());
    }

您还需要在课堂上use以下内容:

use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Configuration;
use Doctrine\ORM\ORMException;
use Doctrine\Common\EventManager;
use Doctrine\DBAL\Connection;

老实说,我很惊讶第二步是必需的,我认为应该可以只使用服务容器来完成。

答案 2 :(得分:3)

至少在Doctrine / ORM 2.4中,EntityManager类的doc字符串明确地不鼓励从Doctrine \ ORM \ EntityManager继承,而是建议从Doctrine \ ORM \ Decorator \ EntityManagerDecorator继承:

/**
 * The EntityManager is the central access point to ORM functionality.
 * ...
 * You should never attempt to inherit from the EntityManager: Inheritance
 * is not a valid extension point for the EntityManager. Instead you
 * should take a look at the {@see \Doctrine\ORM\Decorator\EntityManagerDecorator}
 * and wrap your entity manager in a decorator.
 * ...
 */
/* final */class EntityManager implements EntityManagerInterface
{
    ...

因此,扩展EntityManagerDecorator并进行所需的任何更改。您需要实现create()工厂方法,但现在不需要复制EntityManager的实现:

use Doctrine\ORM\Decorator\EntityManagerDecorator;
use Doctrine\Common\EventManager;
use Doctrine\ORM\Configuration;

class MyEntityManager extends EntityManagerDecorator
{
    /**
     * {@inheritDoc}
     */
    public function persist($entity)
    {
        // do something interesting
        parent::persist($entity);
    }

    public function create($conn, Configuration $config, EventManager $eventManager = null)
    {
        return new self(\Doctrine\ORM\EntityManager::create($conn, $config, $eventManager));
    }
}

然后重写doctrine.orm.entity_manager.class参数以指向您的自定义实体管理器类。

文档并未涵盖所有内容,在许多情况下,您只需阅读代码。

答案 3 :(得分:0)

我发现 扩展实体管理器 的过程非常违反直觉, 尽管对概念有一定的了解,包括依赖项注入,服务定位器,代码生成,缓存和装饰器模式。

希望这个简洁的示例可以为您画一个清晰的图片(此扩展了@ user2563451的答案)

Symfony版本(2018年8月20日星期一13:05:58 CEST)

$ composer info | grep -E -e symfony/framework  -e 'doctrine/(common|orm|dbal)'
doctrine/common             v2.9.0             Common Library for Doctrine projects
doctrine/dbal               v2.8.0             Database Abstraction Layer
doctrine/orm                v2.6.2             Object-Relational-Mapper for PHP
symfony/framework-bundle    v4.1.3             Symfony FrameworkBundle

config / services.yaml

App\Doctrine\ORM\CustomEntityManager:
    public: false # optional afaik
    decorates: doctrine.orm.original_entity_manager
    arguments: [ '@App\Doctrine\ORM\CustomEntityManager.inner' ]

config / packages / doctrine.yaml

doctrine:
    orm:
        auto_generate_proxy_classes: '%kernel.debug%'
        default_entity_manager: original
        entity_managers:
            original:
                connection: from_env
                naming_strategy: doctrine.orm.naming_strategy.underscore
                auto_mapping: false
                mappings:
                    TimeTracking:
                        is_bundle: false
                        type: annotation
                        dir: '%kernel.project_dir%/src/php/Model'
                        prefix: TimeTracking\Model
                        alias: TimeTracking
                        mapping: true
            #mapper_number_5:
            #    (...)

src / php / App / Doctrine / ORM / CustomEntityManager.php

<?php

namespace App\Doctrine\ORM;

use App\Doctrine\ORM\Proxy\SoggyProxyFactory;
use Doctrine\ORM\Decorator\EntityManagerDecorator;
use Doctrine\ORM\Proxy\ProxyFactory;

/**
 * Writes custom proxy-class methods with support for the set-or-get-trait
 * @property  ProxyFactory soggyProxyFactory
 */
class CustomEntityManager extends EntityManagerDecorator
{
    /// SUPER: __construct(EntityManagerInterface $wrapped) { $this->wrapped = $wrapped; }
    private $soggyProxyFactory;
    public function getProxyFactory() {
        $config = $this->getConfiguration();
        if (null === $this->soggyProxyFactory) {
            $this->soggyProxyFactory = new SoggyProxyFactory(
                $this,
                $config->getProxyDir(),
                $config->getProxyNamespace(),
                $config->getAutoGenerateProxyClasses()
            );
        }
        return $this->soggyProxyFactory;
    }
}

引用

http://symfony.com/doc/current/service_container/service_decoration.html

https://symfony.com/doc/current/doctrine/multiple_entity_managers.html