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

时间:2015-07-27 21:37:44

标签: php orm doctrine-orm doctrine factory

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

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

因为我希望能够从SocialMedia对象中查询多个内容,并且每个社交媒体平台都有自己的API,我创建了界面并创建了不同的类,因此他们都可以拥有自己的方法实现

现在,问题当然是我的抽象类和Doctrine。学说在他们的website regarding inheritance上说明了这一点:

  

映射的超类不能是实体,它不是可查询的[...]

现在,如果我有一个SocialMediaFactory并投入一个ID,我想获得相应的对象,例如,Facebook或Instagram类。我不想知道收集它们时究竟是哪个SocialMedia。现在这是一个学说问题,至少是我认为的那样。

我忽略了什么,工厂模式仍然可能吗?或者我应该真正删除抽象类,并创建一个工厂,在SocialMediaInterface实现类的每个表中进行搜索,这在应用程序变大时效率非常低且不可用。

任何见解或指示都会受到赞赏,因为我确信这个问题必须经常出现。我尝试使用Google搜索和搜索Stackoverflow本身,但我无法得到任何相关的问题或答案。

非常感谢你。

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

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

到我的代码。我寄予厚望,但遗憾的是验证员给了我这个错误:

  

[学说\ ORM \映射\ MappingException]     不支持在映射的超类上定义继承信息     s' Portal \ SocialMedia \ Entity \ SocialMediaAbstract'。

不支持羞耻映射器超类。

编辑2 /结论: 我决定使用Class Table Inheritance(就像下面建议的那样)。从类中删除摘要使得仍然可以使用我的工厂。

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

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

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

这将返回一个Instagram对象。我仍然建议你在以后建立自己的工厂以保持可维护性,因为SocialMedia实体可能会在以后更改。

1 个答案:

答案 0 :(得分:2)

自从我使用教条以来已经过去了一段时间,但如果我没记错,doctrine's mapped super classes是Martin Fowler concrete table inheritance pattern的实现。

在那里提到的示例中,Player是映射的超类,其属性分发给所有继承的实体/模型。这里的要点是玩家无法实例化,因此没有自己的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需要注意公共属性保存在基类表中,而所有属性特定于实体的内容保存在实体的表中。然后这些表由id连接,因此在doctrine中继承类型为“JOINED”。

结论:

如果类非常类似且只在功能定义或实现方面有所不同,但具有相同的属性,请使用single table inheritance

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

如果类彼此不真正相关,但仅共享少量公共属性,请使用concrete table inheritance。但这也可以通过PHP's traits来实现,在我看来,这比使用教义的映射超类更容易,更灵活。在PHP特性中,您还可以使用doctrine的注释,因为PHP解释器会正确地将注释分配给您使用这些特征的类。

您仍然可以将SocialMediaFactory与单表或类表继​​承模式一起使用。