如何使用 XML 或 YAML 而非注解映射来定义 Doctrine mappedSuperclass
Posted
技术标签:
【中文标题】如何使用 XML 或 YAML 而非注解映射来定义 Doctrine mappedSuperclass【英文标题】:How to define a Doctrine mappedSuperclass using XML or YAML instead of annotation mapping 【发布时间】:2019-02-05 13:15:56 【问题描述】:以下脚本来自https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/inheritance-mapping.html#mapped-superclasses,仅更改为包含第二个子类。据我了解,MappedSuperclassBase
不能单独存在,必须由一个且只有一个子类扩展(即EntitySubClassOne
或EntitySubClassTwo
),并且与 SQL 的超类型/子类型概念相同。同意吗?
如何使用 YAML 或 XML 而非注解映射来定义超级/子类型?
<?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
【问题讨论】:
在您的链接上,向下滚动到此处:doctrine-project.org/projects/doctrine-orm/en/2.6/reference/… ;-) @rkeet 除非我弄错了,否则该部分仅描述关联覆盖,而有问题的部分被省略并描述为//other fields mapping
。
您的问题是“如何使用 Yaml / XML”。如果您专门访问该链接,那里的代码示例顶部有选项卡,可让您切换语言。如果您阅读该代码,您会看到“如何”在此处映射请求的MappedSuperClass
。 (Yaml:type: mappedSuperclass
,XML:<mapped-superclass name="MyProject\Model\User">
)
@rkeet 但它没有显示 @OneToOne(targetEntity="MappedSuperclassRelated1")
和 @JoinColumn(name="related1_id", referencedColumnName="id")
的等价物,当然,这不是很难转换。更重要的是,它没有解释EntitySubClass
是如何知道它与MappedSuperclassBase
相关联的,而这正是我正在努力的部分。谢谢
如果 Worker
扩展 Person
(超类),那么您有 1 个实体:工人。创建与Worker
的关系(即来自Paycheck
),仅链接到Worker。超类Person
只是创建了一组用于 Worker 的基本属性/默认值。
【参考方案1】:
根据我们的 cmets,我想我看到了您的困惑。因为the docs 在同一页面上同时处理“MappedSuperclass”和“Discriminator”,所以我认为您已经混淆了它们的用途。希望这可以帮助您:
MappedSuperclass
以可重用的方式提供属性/默认值,但它本身永远不能成为实体。这相当于 PHP 的 abstract
类(不能自行实例化)
鉴别器提供“扩展”实体的能力,使其成为另一个实体。例如,拥有Person
实体会为您提供 1 个实体。此实体可以扩展,例如通过Worker
和Manager
。
MappedSuperclass
的一个很好的用例是AbstractEntity
。每个实体都需要一个 ID,一个唯一的标识符。它还为您提供了在 Listeners 等中检查的常见内容。所以,继续创建:
/**
* @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
看看abstract
和MappedSuperclass
是如何声明的?
这是因为(abstract class
和 MappedSuperclass
)都不能自己实例化。你不能做$entity = new AbstractEntity()
,因为它是一个abstract
PHP 类。 Doctrine 也不会为AbstractEntity
创建单独的表。
接下来,创建一个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
上面的Person
,Entity是通过JOINED
继承类型为Class Table Inheritance设置的。这意味着,在数据库级别,表 persons
将与其他实体添加的任何列分开,扩展 Person
。
注意我没有声明DiscriminatorMap
。以下来自文档,由我以粗体突出显示:
注意事项:
@InheritanceType、@DiscriminatorColumn 和 @DiscriminatorMap 必须在作为映射实体层次结构一部分的最顶层类中指定。 @DiscriminatorMap 指定鉴别器列的哪些值将行标识为哪种类型。在上面的例子中,“person”值将一行标识为 Person 类型,“employee”将一行标识为 Employee 类型。 如果类与应用了鉴别器映射的实体类包含在同一命名空间中,则鉴别器映射中的类的名称不需要完全限定。 如果没有提供鉴别图,则自动生成图。自动生成的鉴别器映射包含每个类的小写短名称作为键。
现在,让我们创建一个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
所以,现在我们有了:
MappedSuperclass:AbstractEntity
- 不是独立实体
受歧视:Person
- 是独立实体
“正常”:Worker
- 扩展 Person
注意事项:
MappedSuperclass 无法实例化。因此:您不能创建到它的链接/关系。媲美PHP的abstract class
可识别实体是一个独立的实体,可用作普通实体。您可以毫无问题地与它建立关系
扩展可识别实体的实体是两者的实例。在上面的代码中,这两个都是真的:$worker instanceof Worker
和$worker instanceof Person
,因为Worker
扩展了Person
。但是,$person instanceof Worker
将是 false
!
$workerId = $person->getWorkerId() // generates "method does not exist" fatal
$workerId = $worker->getWorkerId() // generates integer value
希望能够为您解决问题。如果没有,请随时询问。
【讨论】:
感谢 rkeet。在您的示例中,您明确定义了class Person extends AbstractEntity
。但是如果使用 XML 或 YAML 实现,难道不是从 PHP 类开始,因此无法以这种方式定义这种关系吗?
你会以这种方式开始,在此处查看前面的链接:doctrine-project.org/projects/doctrine-orm/en/2.6/reference/… - User
是由 Admin
扩展的 MappedSuperclass 的情况。如果你遵循它,你应该能够让它工作。
啊,我明白了我的困惑的根源。我错误地认为 MappedSuperclass 代表 SQL 超类型/子类型 (learndatamodeling.com/blog/supertype-and-subtype)。我知道无法实例化 MappedSuperclass,但我没有意识到没有与之关联的表!
啊,好吧,我没有在答案中解释这一点 ;-) 但同样,这就像 abstract class
与 class
;-) 因为第一个无法实例化,如一个没有表的实体。后者可以被实例化并且应该有一个关联的数据存储(表)。然后是区分类,其中“单表继承”具有扩展的最父类的“根”表和类表继承,其中每个实体都有自己的表,但连接到其父级(因此它是特定表仅添加其添加的属性)。
再次感谢您的帮助。第一次尝试使用 ORM,这是一段旅程,但开始走到一起。有区别的类是我想要的。以上是关于如何使用 XML 或 YAML 而非注解映射来定义 Doctrine mappedSuperclass的主要内容,如果未能解决你的问题,请参考以下文章
原则 2:有没有办法使用 yaml 或 xml 从 trait 继承映射?
如何将自定义属性添加到 Symfony Doctrine YAML 映射文件