0

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

到目前为止我尝试了什么:

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

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

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

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

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

4

1 回答 1

0

我有完全相同的问题 - 我刚刚从 RedBean 切换到 Doctrine(对于使用 Zend 框架的项目),并且我的类的结构没有考虑到这个问题。核心问题是,据我所知,Doctrine 中的地图与类具有一对一的关系。我们正在寻找一种方法来拥有一个使用抽象类(DefaultUser)中的映射的具体类(UserEntity)。我的解决方案可能有点像黑客(我只使用 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。

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

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

于 2012-06-03T12:41:26.457 回答