在 Doctrine2 中是否有任何关于在抽象 class 上使用 @Entity 注释或将抽象 class 放在鉴别器映射中的禁忌症?

Is there in Doctrine2 any contraindications about use @Entity annotation on an abstract class or about put an abstract class in discriminator map?

我没有找到相关信息。

很多人告诉我,将@Entity 注释放在抽象上是没有意义的 class。从我的角度来看,当我制作 PHP 抽象 class 时,我主要期望没有 PHP 代码可以使用 new 运算符创建实例。

有些人告诉我在像 ChildrenAbstract 这样的 classes 上使用 @MappedSuperClass,但除非我删除似乎无用的 @Entity 注释,因为我有时需要 @MappedSuperClass 不允许的映射。

很多人问我为什么,所以这里基本上是为什么:

ParentAbstract.php

/**
 * @ORM\Table(name="ParentAbstract")
 * @ORM\Entity(repositoryClass="App\Repository\ParentAbstractRepository")
 * @ORM\InheritanceType("JOINED")
 * @ORM\DiscriminatorColumn(name="discr", type="string")
 * @ORM\DiscriminatorMap({"childrenAbstract" = "ChildrenAbstract", "concreteA" = "ConcreteA", "concreteB" = "ConcreteB"})
 */
abstract class ParentAbstract
{
   ...
}

ChildrenAbstract.php

/**
 * @ORM\Table(name="ChildrenAbstract")
 * @ORM\Entity(repositoryClass="App\Repository\ChildrenAbstractRepository")
 */
abstract class ChildrenAbstract extends ParentAbstract
{   
   /** * @ORM\Column(type="string", nullable=true) */
   private $picture;
}

ConcreteA.php

/**
 * @ORM\Table(name="ConcreteA")
 * @ORM\Entity(repositoryClass="App\Repository\ConcreteARepository")
 */
class ConcreteA extends ChildrenAbstract
{   
   ...
}

ConcreteB.php

/**
 * @ORM\Table(name="ConcreteB")
 * @ORM\Entity(repositoryClass="App\Repository\ConcreteBRepository")
 */
class ConcreteB extends ChildrenAbstract
{   
   ...
}

ChildrenAbstractController.php

class ChildrenAbstractController extends AbstractController
{   
   /**
     * @Route("/home/childrenabstract/get/picture/{id}", name="get_childrenabstract_picture")
     */
   public function getChildrenAbstractPicture(Request $request, int $id) : Response
   {
       $childrenAbstract = $this->getDoctrine()->getRepository(ChildrenAbstract::class)->findById($id);

       if(!$childrenAbstract)
       {
           throw new \Exception("childrenAbstract don't exists !");
       }

       $response = new BinaryFileResponse("../path/".$childrenAbstract->getId()."/".$childrenAbstract->getPicture());
       $response->headers->set('Content-Type', 'image/' . 'png');
       $response->setContentDisposition(ResponseHeaderBag::DISPOSITION_INLINE);

       return $response;
   }    

ConcreteAFront.html.twig

{% for concreteA in container.concreteAs %}
   <td>{{ form_label(form.picture) }}</td><td><img src="{{ path('get_childrenabstract_picture', {id:concreteA.id}) }}" /></td>
{% endfor %}

ConcreteBFront.html.twig

{% for concreteB in container.concreteBs %}
   <td>{{ form_label(form.picture) }}</td><td><img src="{{ path('get_childrenabstract_picture', {id:concreteB.id}) }}" /></td>
{% endfor %}

我需要一个 "generic" 路由来与具体结构的某些部分交互,有时 AbctractChildren.php 中的映射与 @ORM\ManyToOne、@ORM\ManyToMany 更复杂。 ..

关键是它运行良好。或者这似乎非常有效。我需要确定 Doctrine2 是为了支持这种方式而设计的,或者是否应该避免这种做法。

TL;DR:避免在抽象上放置实体注释 class。首先,它不寻常,可能会让未来的维护者感到困惑。其次,它违背了 Doctrine 预期的工作方式,因此可能会在未来的 Doctrine 版本中停止工作。

好问题!让我们去看文档。来自 Basic Mapping section:

... Doctrine only knows about your entities because you will describe their existence and structure using mapping metadata, which is configuration that tells Doctrine how your entity should be stored in the database.

With no additional information, Doctrine expects the entity to be saved into a table with the same name as the class in our case Message.

并且来自 Inheritance Mapping 部分:

A mapped superclass is an abstract or concrete class that provides persistent entity state and mapping information for its subclasses, but which is not itself an entity. Typically, the purpose of such a mapped superclass is to define state and mapping information that is common to multiple entity classes.

所以,Doctrine 期待两件事:

  1. 类注解为@Entity会被当作对象来操作,每个对象代表table.
  2. 中的一行数据
  3. 类 注释为 @MappedSuperclass 不会作为对象进行操作,也不会表示一行数据

abstract class 根据定义不能归入类别 #1,因此它只能归入类别 #2。无论如何,这就是理论。实际上,您正在寻求重用,那就是 一定要使用它,这就是 Doctrine 使之成为可能的原因!

您表示您在实施 MappedSuperclass 和关系时遇到了问题,我猜您遇到了如下错误:

[Doctrine\ORM\Mapping\MappingException] It is illegal to put an inverse side one-to-many or many-to-many association on mapped superclass 'App...\AbstractFoo#thing'.

发生这种情况是因为 language implementation limitation and can be fixed by opening your properties from private to protected

如果您遇到其他问题,请 post 解决。如果 Mappedsuperclass 不能用于处理您的用例,那么要么您的特定用例非常独特,要么是 Doctrine 中的错误。无论哪种方式,都值得进一步评估。