问题
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'sabstract
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 byWorker
andManager
.
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
- extendsPerson
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 theWorker
extendsPerson
. However,$person instanceof Worker
will befalse
!
$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