How to define a Doctrine mappedSuperclass using XML or YAML instead of annotation mapping

久未见 提交于 2020-03-05 03:26:57

问题


The following script comes from https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/inheritance-mapping.html#mapped-superclasses, and was only changed to include a second sub-class. It is my understanding that MappedSuperclassBase cannot exist by itself but must be extended by one and only one sub-class (i.e. either EntitySubClassOne or EntitySubClassTwo), and is the same concept as supertype/subtype for SQL. Agree?

How is a super/sub type defined using either YAML or XML instead of annotation mapping?

<?php
/** @MappedSuperclass */
class MappedSuperclassBase
{
    /** @Column(type="integer") */
    protected $mapped1;
    /** @Column(type="string") */
    protected $mapped2;
    /**
     * @OneToOne(targetEntity="MappedSuperclassRelated1")
     * @JoinColumn(name="related1_id", referencedColumnName="id")
     */
    protected $mappedRelated1;

    // ... more fields and methods
}

/** @Entity */
class EntitySubClassOne extends MappedSuperclassBase
{
    /** @Id @Column(type="integer") */
    private $id;
    /** @Column(type="string") */
    private $name;

    // ... more fields and methods
}

/** @Entity */
class EntitySubClassTwo extends MappedSuperclassBase
{
    /** @Id @Column(type="integer") */
    private $id;
    /** @Column(type="string") */
    private $name;

    // ... more fields and methods
}

回答1:


Based on our comments, I think I see your confusion. Because the docs handle both "MappedSuperclass" and "Discriminator" on the same page, I think you've mixed up their uses in your head. Hopefully this can help you:

  • A MappedSuperclass provides properties/defaults in a re-usable way, but it can never be an Entity by itself. This is comparable to PHP's abstract classes (which cannot be instantiated on their own)
  • A Discriminator provides the ability to "extend" an Entity, making it another Entity. For example, having a Person Entity gives you 1 Entity. This Entity can be extended, for example by Worker and Manager.

A good use-case for a MappedSuperclass would be an AbstractEntity. Every Entity needs an ID, a unique identifier. It also gives you something common to check against in Listeners and such. So, go ahead and create:

/**
 * @ORM\MappedSuperclass
 */
abstract class AbstractEntity
{
    /**
     * @var int
     * @ORM\Id
     * @ORM\Column(name="id", type="integer", options={"unsigned":true})
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    protected $id;

    // getter / setter
}

See how this is both declared abstract and MappedSuperclass?

This is because neither (abstract class and MappedSuperclass) cannot be instantiated on their own. You cannot do $entity = new AbstractEntity() because it's an abstract PHP class. Neither will Doctrine create a separate table for AbstractEntity.

Next, create a Person:

/**
 * @ORM\Entity
 * @ORM\Table(name="persons")
 *
 * @InheritanceType("JOINED")
 * @DiscriminatorColumn(name="discr", type="string")
 */
class Person extends AbstractEntity
{
    /**
     * @var string
     * @ORM\Column(name="name", type="string", length=255, nullable=false)
     */
    protected $name;

    // getter / setter
}

The above, Person, Entity is setup for Class Table Inheritance through the JOINED inheritance type. Meaning that, on the database level, the table persons will be separate from any columns added by other entities, extending Person.

Notice how I did not declare DiscriminatorMap. Below from the docs, highlighted in bold by me:

Things to note:

  • The @InheritanceType, @DiscriminatorColumn and @DiscriminatorMap must be specified on the topmost class that is part of the mapped entity hierarchy.
  • The @DiscriminatorMap specifies which values of the discriminator column identify a row as being of which type. In the case above a value of "person" identifies a row as being of type Person and "employee" identifies a row as being of type Employee.
  • The names of the classes in the discriminator map do not need to be fully qualified if the classes are contained in the same namespace as the entity class on which the discriminator map is applied.
  • If no discriminator map is provided, then the map is generated automatically. The automatically generated discriminator map contains the lowercase short name of each class as key.

Now, let's create a Worker:

/**
 * @ORM\Entity
 * @ORM\Table(name="workers")
 */
class Worker extends Person
{
    /**
     * @var int
     * @ORM\Column(name="worker_id", type="integer", length=11, nullable=false)
     */
    protected $workerId;

    // getter / setter
}

So, now we've got:

  • MappedSuperclass: AbstractEntity - is not a stand-alone Entity
  • Discriminated: Person - is a stand-alone Entity
  • "normal": Worker - extends Person

Things to note:

  • A MappedSuperclass can not be instantiated. As such: you can not create links/relations to it. Comparable with PHP's abstract class
  • A Discriminated Entity is one which also stands alone and can be used as a normal Entity. You can create relations to and from it, without an issue
  • An Entity extending a Discriminated Entity is an instance of both. In the above code these are both true: $worker instanceof Worker and $worker instanceof Person, because the Worker extends Person. However, $person instanceof Worker will be false!

$workerId = $person->getWorkerId() // generates "method does not exist" fatal

$workerId = $worker->getWorkerId() // generates integer value


Hope that managed to clear stuff up for you. If not, feel free to ask.



来源:https://stackoverflow.com/questions/54535298/how-to-define-a-doctrine-mappedsuperclass-using-xml-or-yaml-instead-of-annotatio

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!