我目前正在使用Symfony2和Doctrine2,但我必须覆盖Doctrine2 EntityManager并添加一些“取消删除”功能(内部的ACL)。
所以我想知道:有没有办法覆盖EntityManager类并在Symfony2中指定Doctrine2以将其用作EntityManager的实现?
感谢您的帮助!
答案 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的答案)
$ 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
App\Doctrine\ORM\CustomEntityManager:
public: false # optional afaik
decorates: doctrine.orm.original_entity_manager
arguments: [ '@App\Doctrine\ORM\CustomEntityManager.inner' ]
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:
# (...)
<?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