在学说中扩展实体的最佳方式

问题描述 投票:0回答:1

我在我制作的一个小框架中有一个用户实体。现在我想在几个项目中使用这个用户实体。 但在某些项目中,我想在不修改文件的情况下向用户实体添加一些字段。

到目前为止我尝试过的:

我在 DefaultUser Bundle 中创建了一个新的 DefaultUser 实体,并使该 User 实体成为映射的超类。但现在我无法在其他实体中建立关联,例如

    /*
     * @ORM\ManyToOne(targetEntity="User", inversedBy="jobs")
     * @ORM\JoinColumn(name="user", referencedColumnName="id")
     */
     private $user;

因为Doctrine在用户实体中找不到id列。仅当我指定 DefaultUser 实体时这才有效。根据学说文档,如果只有一片叶子存在,则这只适用于多对多关联。

然后我尝试了单表继承。这工作正常,但如果我想扩展在多个项目中共享的用户实体,我必须修改 DiscriminatorMap...

那么扩展 UserEntity 的最佳方式是什么?

php symfony doctrine-orm
1个回答
0
投票

我有完全相同的问题 - 我刚刚从 RedBean 切换到 Doctrine (对于使用 Zend Framework 的项目),并且我的类的结构没有考虑到这个问题。据我所知,核心问题是 Doctrine 中的地图与类具有一对一的关系。我们正在寻找一种方法,让一个具体类(UserEntity)使用抽象类(DefaultUser)中的映射。我的解决方案可能是一个 hack(我只使用了 Doctrine 几天),但至少适用于 YAML:

创建一个扩展 YAML 驱动程序的新映射驱动程序,并使用如下内容重写 _loadMappingFile 方法:

class MyLibrary_Doctrine_Mapping_Driver_YamlExtended extends MyLibrary_Doctrine_Mapping_Driver_YamlExtended
{
protected $_basicEntityFolder;

protected function _loadMappingFile($file)
{
$entMaps = parent::_loadMappingFile($file);

//merge this with any extensions if defined
foreach($entMaps as $ent => $map)
  { //load the relevant map
    if (!isset($map['extendEntity'])) {
      continue;
    }
    $fileName = $this->_basicEntityFolder . DIRECTORY_SEPARATOR .  str_replace('\\', '.', $map['extendEntity']) . $this->_fileExtension;

$extendedMaps = $this->_loadMappingFile($fileName);
if (!is_array($extendedMaps[$map['extendEntity']])) {
  throw new MyProject_Doctrine_Exception("Entity to extend from could not be found.");
}
//merge so that the file lower in the class hierachy always overrides the higher
$map = array_merge($extendedMaps[$map['extendEntity']], $map);

//clear the  extendEntity value
unset($map['extendEntity']);
$entMaps[$ent] = $map;
  }
    return $entMaps;
}

public function setExtendedEntitiesFolder($path)
{
  $this->_basicEntityFolder = $path;
}
}

然后我有两个 yaml 文件,位于不同的文件夹中,如下所示:

#MyApplication/Entities/Maps/Entities.User.dcm.yml
Entities\User:
 extendEntity: LibraryEntities\User

这是应用程序中的文件。然后在图书馆我有

#Library/Entities/Maps/ExtendedEntities/LibraryEntities.User.dcm.yml
LibraryEntities\User:
type: entity
table: user
fields:
  username:
    type: text
    nullable: true
password:
  type: text
  nullable: true
defaultProfile:
  type: text
  nullable: true
  column: default_profile

它位于 ExtendedEntities 文件夹中的原因是,我可以使用普通命名空间在库中定义mappedSuperclasses,并且 Doctrine 会在类扩展它们时自动加载它们,但这些扩展实体位于 Doctrine 通常的类继承加载的路径之外(如果它们都在正常的文件夹结构中,那么对于例如“class ApplicationUser extends LibraryUser”Doctrine 会尝试加载 LibraryUser 的配置,因为它会找到它,然后导致您已经遇到的相同错误)。

然后当我设置我的 $em 时,我将其提供给我的驱动程序:

$driverImpl = new MyLibrary_Doctrine_Mapping_Driver_YamlExtended(array(APPLICATION_PATH . '/entities/maps', 
                                                                   LIBRARY_PATH . '/Entities/Maps'));
$driverImpl->setExtendedEntitiesFolder(LIBRARY_PATH . '/Entities/Maps/ExtendedEntities');

请注意,此解决方案允许由“extendEntity”定义的继承链(因为 _loadMappingFile 方法是递归的)。此外,链下游的任何配置文件都可以覆盖已定义的任何属性,因此即使在您的库 yaml 中您有:

 username:
    type: text

假设您有一个项目,其中的用户名是整数,您可以简单地在应用程序配置中使用

覆盖它
 username:
    type: int

或者其他什么。

因此这解决了在基类上定义 Doctrine 风格继承的问题。在每个项目中,您都可以根据自己的喜好定义 DiscriminatorMap。

原则上,相同的解决方案可以应用于注释,尽管扩展注释驱动程序稍微复杂一些,因为它不是简单地通过一次性读取一个文件并将其转换为数组来读取元数据,而是发出大量请求注释阅读器,这意味着实现这个结构会更棘手。

我很想知道其他人是如何解决这个问题的。

© www.soinside.com 2019 - 2024. All rights reserved.