所以我偶然发现了这个障碍,我必须创建一个抽象类和一个工厂来创建更具体的类的对象,这些类扩展抽象类并实现更具体的对象方法。
简单地说,我有一个 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 classes是 concrete table inheritance pattern 的实现作者:马丁·福勒。
在上面提到的示例中,Player
是映射的父类(super class),其属性分布到所有继承实体/模型。这里的要点是玩家无法被实例化,因此没有自己的 id。相反,每个继承模型都有自己的 id,它们都是相互独立的。
我认为您正在寻找的模式是 single table inheritance或class 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/