php - Doctrine ORM 和具有抽象类策略的工厂

标签 php orm doctrine-orm doctrine factory

所以我偶然发现了这个障碍,我必须创建一个抽象类和一个工厂来创建更具体的类的对象,这些类扩展抽象类并实现更具体的对象方法。

简单地说,我有一个 SocialMediaAbstract 类。扩展类有 Facebook、Instagram,它们实现了 SocialMediaInterface。 Facebook、Instagram 等都保存在数据库中,具有 id、名称和其他几个属性,这些属性都在扩展类中使用,因此是一个抽象类。

因为我希望能够从 SocialMedia 对象中查询一些内容,并且每个社交媒体平台都有自己的 API,所以我创建了接口(interface)并创建了不同的类,以便它们都可以拥有自己的这些方法的实现.

现在,问题当然出在我的抽象类和 Doctrine 上。 Doctrine 在他们的 website regarding inheritance 上这么说。 :

A mapped superclass cannot be an entity, it is not query-able [...]

现在,如果我有一个 SocialMediaFactory 并输入一个 ID,我想获取相应的对象,例如 Facebook 或 Instagram 类。当我收集它们时,我不想确切地知道它是哪个社交媒体。现在这是一个 Doctrine 问题,至少我是这么认为的。

我是否忽略了一些事情,工厂模式还可能吗?或者我真的应该删除抽象类,并创建一个在 SocialMediaInterface 实现类的每个表中进行搜索的工厂,当应用程序变得更大时,这似乎非常低效且难以维护。

任何见解或指示将不胜感激,因为我确信这个问题一定会更频繁地出现。我尝试在 Stackoverflow 上进行谷歌搜索,但找不到任何相关问题或答案。

提前非常感谢您。

编辑: 我遇到了这个有趣的可能性:Class Table Inheritance 。这意味着添加:

 * @ORM\InheritanceType("JOINED")
 * @ORM\DiscriminatorColumn(name="discr", type="string")
 * @ORM\DiscriminatorMap({"facebook" = "Facebook", "instagram" = "Instagram"})

到我的代码。我抱有很高的期望,但遗憾的是验证器给了我这个错误:

[Doctrine\ORM\Mapping\MappingException] It is not supported to define inheritance information on a mapped superclas s 'Portal\SocialMedia\Entity\SocialMediaAbstract'.

遗憾的是,不支持映射器父类(super class)。

编辑 2/结论: 我决定使用类表继承(就像下面建议的答案一样)。从类中删除抽象使得仍然可以使用我的工厂。

但是,我现在使用具体类作为抽象类,这感觉不对。我在 docblock 中记录了不应从此类实例化任何对象。

一个小旁注:Doctrine 的实体管理器或多或少已经提供了工厂:

$socialMedia = $entityManager->find('Portal\SocialMedia\Entity\SocialMedia', 2);

这会返回一个 Instagram 对象。我仍然建议您在其之上构建自己的工厂,以便稍后进行维护,因为 SocialMedia 实体稍后可能会发生变化。

最佳答案

自从我从事 Doctrine 以来已经有一段时间了,但如果我没记错的话,doctrine's mapped super classesconcrete table inheritance pattern 的实现作者:马丁·福勒。

在上面提到的示例中,Player 是映射的父类(super class),其属性分布到所有继承实体/模型。这里的要点是玩家无法被实例化,因此没有自己的 id。相反,每个继承模型都有自己的 id,它们都是相互独立的。

我认为您正在寻找的模式是 single table inheritanceclass table inheritance (看看doctrine's inheritance types)。


Single table inheritance在 Doctrine 的继承类型“SINGLE_TABLE”中实现,其中所有实体都有一个表。它们共享完全相同的属性和相同的 id 池,这意味着您可以“放入”一个 id,获取对象并检查类型(Facebook、Instagram 等)。

缺点是,如果您在任何实体中获得可能为 NULL 的属性,则如果其他实体没有此属性或不需要它,您可能会遇到问题。这意味着您必须将给定属性设置为其他实体中的虚拟值,才能将它们保存到数据库表中。


Class table inheritance通过将每个实体保存在自己的表中,同时仍然能够共享 id 池,克服了这个问题,因为 Doctrine 注意将公共(public)属性保存在基类表中,而特定于实体的所有属性都保存在实体的表。然后,这些表通过 id 连接起来,因此在 Doctrine 中继承类型为“JOINED”。


结论:

使用single table inheritance如果类非常相似,仅在函数定义或实现上有所不同,但具有相同的属性。

使用class table inheritance如果类具有不同的属性,则存储在单个表中会出现问题。

使用concrete table inheritance如果类彼此之间并不真正相关,而仅共享少量公共(public)属性。但这也可以通过 PHP's traits 来实现,在我看来,它比 Doctrine 的映射父类(super class)更容易、更灵活地使用。在 PHP 特征中,您还可以使用 Doctrine 的注释,因为 PHP 解释器会正确地将注释分配给您使用特征的类。

您应该仍然能够通过单表或类表继​​承模式使用 SocialMediaFactory。

关于php - Doctrine ORM 和具有抽象类策略的工厂,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31663756/

相关文章:

php - ManyToMany 没有删除

PHP Mysql 通过某些字段进行分组加1

php - Magento 1.6 : Using MySQL datetime fields with resource models

php - Laravel 4.1 Eloquent - 过滤关系集合

symfony - 多个实体的电子邮件日志表

Symfony Doctrine Hydrator - 使用定制 Hydrator 我失去了 ManyToOne 关系

php - Python OOP 与 PHP OOP 相比如何?

php - 生成 OpenSSL 私钥和公钥

orm - 请解释 Laravel ORM 中的foreign_key 和 local_key 关系

c# - 2012年用linq2sql启动一个新的企业大型web应用是否明智