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

Php 具有抽象类策略的ORM和工厂,php,orm,doctrine-orm,doctrine,factory,Php,Orm,Doctrine Orm,Doctrine,Factory,所以我遇到了这个障碍,我必须创建一个抽象类和一个工厂来创建更特定类的对象,这些类扩展了抽象类并实现了更特定的对象方法 简单地说,我得到了一个社会中介抽象类。扩展类有Facebook、Instagram,它们实现了一个SocialMediaMainterface。Facebook、Instagram等都保存在db中,带有一个id、一个名称和多个属性,这些属性都在扩展类中使用,因此是一个抽象类 因为我希望能够从SocialMedia对象中查询一些内容,并且每个社交媒体平台都有自己的API,所以我制作

所以我遇到了这个障碍,我必须创建一个抽象类和一个工厂来创建更特定类的对象,这些类扩展了抽象类并实现了更特定的对象方法

简单地说,我得到了一个社会中介抽象类。扩展类有Facebook、Instagram,它们实现了一个SocialMediaMainterface。Facebook、Instagram等都保存在db中,带有一个id、一个名称和多个属性,这些属性都在扩展类中使用,因此是一个抽象类

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

现在,问题当然在于我的抽象阶级和学说。教条在他们身上说:

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

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

我是否忽略了什么,工厂模式是否仍然可行?或者,我真的应该删除抽象类,创建一个工厂,在SocialMediaMainterface实现类的每个表中进行搜索,当应用程序变得更大时,这看起来效率很低,而且不可维护

如果您有任何见解或建议,我们将不胜感激,因为我相信这个问题一定经常出现。我试着用谷歌搜索Stackoverflow本身,但我找不到任何相关的问题或答案

事先非常感谢

编辑: 我遇到了一个有趣的可能性:。这意味着增加:

 * @ORM\InheritanceType("JOINED")
 * @ORM\DiscriminatorColumn(name="discr", type="string")
 * @ORM\DiscriminatorMap({"facebook" = "Facebook", "instagram" = "Instagram"})
我的代码。我有很高的期望,但遗憾的是验证器给了我这个错误:

[条令\ORM\Mapping\MappingException] 不支持在映射的超级las上定义继承信息 s'Portal\SocialMedia\Entity\SocialMediaAbstract'

不支持映射器超类

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

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

一点旁注:条令的实体经理或多或少已经提供了工厂:

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

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

自从我使用条令以来,已经过了一段时间,但如果我没记错的话,这是Martin Fowler的实现

在这里提到的示例中,
Player
是映射的超类,其属性分布到所有继承实体/模型。这里的要点是,玩家不能被实例化,因此没有自己的id。相反,每个继承模型都有自己的id,这些id彼此独立

我认为你正在寻找的模式是非此即彼(看看)


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

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


通过将每个实体保存在自己的表中,同时仍然能够共享id池,克服了这个问题,因为doctrine注意将公共属性保存在基类表中,而特定于实体的所有属性都保存在实体的表中。然后,这些表由id连接,因此在原则中继承类型为“joined”


结论:

如果类非常相似,并且仅在函数定义或实现方面不同,但具有相同的属性,则使用

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

如果类之间没有真正的关联,但只共享少量公共属性,则使用。但这也可以通过实现,在我看来,这比理论的映射超类更容易、更灵活地使用。在PHP特性中,您还可以使用doctrine的注释,因为PHP解释器将正确地将注释分配给您在其中使用特性的类


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

如果需要
类表继承,请删除
@MappedSuperclass
注释。您不再需要它了,这是一种不同的继承模式,请参见我的答案以获得解释:)我刚决定通过删除抽象部分来进行类表继承,当我回来时,您提出了这一点。还是谢谢你。问题是,以一种纯粹的方式,我使用一个具体的类作为一个抽象类。我想我必须在文件中记录它不应该被实例化。