- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在开发一个使用 Doctrine 2 ORM 的 Symfony 2.3 项目。正如预期的那样,功能被拆分并分组到大部分独立的包中,以允许在其他项目中重用代码。
我有一个 UserBundle 和一个 ContactInfoBundle。联系信息是分开的,因为其他实体可能具有关联的联系信息,但是可以构建一个用户不需要所述联系信息的系统并不是不可想象的。因此,我非常希望这两个不共享任何硬链接(hard link)。
但是,创建从 User 实体到 ContactInfo 实体的关联映射会创建对 ContactInfoBundle 的硬依赖,一旦禁用捆绑包,Doctrine 就会抛出 ContactInfo 不在其任何注册 namespace 内的错误。
我的调查发现了几种应该解决这个问题的策略,但它们似乎都没有完全发挥作用:
最佳答案
我终于设法为这个问题找到了一个适合我的项目的解决方案。作为介绍,我应该说我的架构中的捆绑包是“星状”布局的。我的意思是我有一个核心或基本包,它作为基本依赖模块并存在于所有项目中。所有其他捆绑软件都可以依赖它,并且只能依赖它。我的其他捆绑包之间没有直接依赖关系。我很确定这个提议的解决方案在这种情况下会起作用,因为架构很简单。我还应该说,我担心这种方法可能会涉及调试问题,但它可以使它很容易打开或关闭,例如,取决于配置设置。
基本想法是安装我自己的 ResolveTargetEntityListener,如果相关实体丢失,它将跳过关联实体。如果缺少绑定(bind)到接口(interface)的类,这将允许执行过程继续。可能没有必要在配置中强调拼写错误的含义——找不到类,这可能会产生难以调试的错误。这就是为什么我建议在开发阶段将其关闭,然后在生产阶段将其重新打开。这样,所有可能的错误都会被教义指出来。
执行
该实现包括重用 ResolveTargetEntityListener 的代码并将一些附加代码放入 remapAssociation
方法。这是我的最终实现:
<?php
namespace Name\MyBundle\Core;
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
use Doctrine\ORM\Mapping\ClassMetadata;
class ResolveTargetEntityListener
{
/**
* @var array
*/
private $resolveTargetEntities = array();
/**
* Add a target-entity class name to resolve to a new class name.
*
* @param string $originalEntity
* @param string $newEntity
* @param array $mapping
* @return void
*/
public function addResolveTargetEntity($originalEntity, $newEntity, array $mapping)
{
$mapping['targetEntity'] = ltrim($newEntity, "\\");
$this->resolveTargetEntities[ltrim($originalEntity, "\\")] = $mapping;
}
/**
* Process event and resolve new target entity names.
*
* @param LoadClassMetadataEventArgs $args
* @return void
*/
public function loadClassMetadata(LoadClassMetadataEventArgs $args)
{
$cm = $args->getClassMetadata();
foreach ($cm->associationMappings as $mapping) {
if (isset($this->resolveTargetEntities[$mapping['targetEntity']])) {
$this->remapAssociation($cm, $mapping);
}
}
}
private function remapAssociation($classMetadata, $mapping)
{
$newMapping = $this->resolveTargetEntities[$mapping['targetEntity']];
$newMapping = array_replace_recursive($mapping, $newMapping);
$newMapping['fieldName'] = $mapping['fieldName'];
unset($classMetadata->associationMappings[$mapping['fieldName']]);
// Silently skip mapping the association if the related entity is missing
if (class_exists($newMapping['targetEntity']) === false)
{
return;
}
switch ($mapping['type'])
{
case ClassMetadata::MANY_TO_MANY:
$classMetadata->mapManyToMany($newMapping);
break;
case ClassMetadata::MANY_TO_ONE:
$classMetadata->mapManyToOne($newMapping);
break;
case ClassMetadata::ONE_TO_MANY:
$classMetadata->mapOneToMany($newMapping);
break;
case ClassMetadata::ONE_TO_ONE:
$classMetadata->mapOneToOne($newMapping);
break;
}
}
}
switch
之前的静默返回用于映射实体关系的语句。如果相关实体的类不存在,则该方法只是返回,而不是执行错误的映射并产生错误。这也意味着缺少字段(如果它不是多对多关系)。在这种情况下,外键只会在数据库中丢失,但由于它存在于实体类中,所以所有代码仍然有效(如果不小心调用了外键的 getter 或 setter,您将不会收到缺少方法的错误)。
doctrine.orm.listeners.resolve_target_entity.class: Name\MyBundle\Core\ResolveTargetEntityListener
关于symfony - 如何在 Symfony 2 中进行可选的跨捆绑关联?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17545157/
我是一名优秀的程序员,十分优秀!