所以我偶然发现了这个障碍,我必须创建一个抽象类和工厂来创建更具体类的对象,这些类扩展抽象类并实现更具体的对象方法。
简单地说,我有一个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实体可能会在以后更改。
答案 0 :(得分:2)
自从我使用教条以来已经过去了一段时间,但如果我没记错,doctrine's mapped super classes是Martin Fowler concrete table inheritance pattern的实现。
在那里提到的示例中,Player
是映射的超类,其属性分发给所有继承的实体/模型。这里的要点是玩家无法实例化,因此没有自己的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需要注意公共属性保存在基类表中,而所有属性特定于实体的内容保存在实体的表中。然后这些表由id连接,因此在doctrine中继承类型为“JOINED”。
结论:
如果类非常类似且只在功能定义或实现方面有所不同,但具有相同的属性,请使用single table inheritance。
如果类具有存储在单个表中存在问题的不同属性,请使用class table inheritance。
如果类彼此不真正相关,但仅共享少量公共属性,请使用concrete table inheritance。但这也可以通过PHP's traits来实现,在我看来,这比使用教义的映射超类更容易,更灵活。在PHP特性中,您还可以使用doctrine的注释,因为PHP解释器会正确地将注释分配给您使用这些特征的类。
您仍然可以将SocialMediaFactory与单表或类表继承模式一起使用。