Symfony2 - 如何动态获取Doctrine实体的实体管理器

时间:2015-10-20 23:59:18

标签: symfony doctrine-orm entitymanager

我们正在建立一个拥有许多不同供应商和客户站点的CMS和网站构建平台,因此有很多不同的内容类型实体,这些实体由通用控制器和帮助服务编辑,这些实体并非必然(容易地知道实体经理对于给定实体是什么。

注意:我们有几个entityManagers来分隔对不同数据库的访问,例如:全球,结算,本地等

在很多情况下,我们需要检测实体的EntityManager是什么。例如,我们有一个MediaHelper,可以动态地将数据库中的媒体与实体上的匹配字段相关联(这不会与关联一起工作,因为媒体必须与字面上的任何实体连接,你不能拥有那种动态关联,我们不想要一百个不同的关联。

媒体是由本地'管理的捆绑包。 EntityManager的。但该实体可能位于全球范围内。 EntityManager(您不能假设它在同一个实体管理器中)。因此,我们需要为正确的实体检测并保留正确的实体经理。

那么您如何建议动态检测实体的entityManager?

原始自定义方法

注意:接受的答案是一个更好的解决方案。这只是出于档案目的。

这是一个有效的简单解决方案。但我不太了解Symfony和Doctrine,知道这是不是一个坏主意?还有其他人知道吗?如果没有,我不知道为什么这不会作为Doctrine实用程序进入核心。

我创建了一个EntityHelper服务,它将Doctrine服务注入其中:

gutensite_cms.entity_helper:
    class: Gutensite\CmsBundle\Service\EntityHelper
    arguments:
        - "@doctrine"

然后在实体助手中有一个简单的函数来获取实体的实体管理器(config.yml已经注册了实体管理器的包):

/**
 * Automagically find the entityManager for an entity. 
 * @param $entity
 * @return mixed
 */
public function getManagerForEntity($entity) {
    $className = \Doctrine\Common\Util\ClassUtils::getRealClass(get_class($entity));
    foreach (array_keys($this->doctrine->getManagers()) as $name) {
        if(in_array($className, $this->doctrine->getManager($name)->getConfiguration()->getMetadataDriverImpl()->getAllClassNames())) return $em;
    }
}

注意:Doctrine Registry#getAliasNamespace已经做了几乎与此foreach循环相同的事情,我只是修改了想法以返回实体管理器而不是命名空间,例如

public function getAliasNamespace($alias) {
    foreach (array_keys($this->getManagers()) as $name) {
        try {
            return $this->getManager($name)->getConfiguration()->getEntityNamespace($alias);
        } catch (ORMException $e) {
        }
    }
    throw ORMException::unknownEntityNamespace($alias);
}

更新10/21/15:根据@ Cerad的建议更新实体检测代码。

2 个答案:

答案 0 :(得分:1)

根据@qooplmao的建议,Doctrine核心中已有一个简单的方法。

// 1) get the real class for the entity with the Doctrine Utility.
$class = \Doctrine\Common\Util\ClassUtils::getRealClass(get_class($entity))

// 2) get the manager for that class. 
$entityManager = $this->container->get('doctrine')->getManagerForClass($class);

2015年10月22日更新根据Cerad和Qooplmao的建议

答案 1 :(得分:0)

您是否可以为实体管理器提供适合其上下文的别名?您可以谈论Global,Billing,Local,例如:

'service_manager' => array(
    'aliases' => array(
        'global_entity_manager' => 'My\Global\EntityManager',
        'billing_entity_manager' => 'My\Billing\EntityManager', 
        'local_entity_manager' => 'My\Local\EntityManager',
    ),
)

您还可以将实体管理器映射到实体的命名空间。 因此,假设您的全局实体的文件夹为Global\Entity,那么您可以为实体管理器为这些实体Global\Entity\EntityManager添加别名。此解决方案的优点是您可以将多个名称空间映射到同一个实体管理器,因此您的BillingGlobal实体可以轻松共享同一个实体管理器:

'service_manager' => array(
    'aliases' => array(
        'Global\Entity\EntityManager' => 'My\Global\EntityManager',
        'Billing\Entity\EntityManager' => 'My\Global\EntityManager', // <-same name
        'Local\Entity\EntityManager' => 'My\Local\EntityManager',
    ),
)

仅当一个命名空间中的实体由同一个EntityManager实例管理时才有效。我几乎不相信在任何项目中都不会出现这种情况,但是否则你应该重新组织一下? :d