Inheritance Mapping

Doctrine currently offers two supported methods of inheritance: single collection and collection per class inheritance.

Mapped Superclasses

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

Just like non-mapped classes, mapped superclasses may appear in the middle of an otherwise mapped inheritance hierarchy (through single collection or collection per class) inheritance.

A mapped superclass cannot be a document and is not queryable.

Example:

1<?php namespace Documents; #[MappedSuperclass] abstract class BaseDocument { }
2
3
4
5
6
7
8

Single Collection Inheritance

In single collection inheritance, each document is stored in a single collection and a discriminator field is used to distinguish one document type from another.

Simple example:

1<?php namespace Documents; #[Document] #[InheritanceType('SINGLE_COLLECTION')] #[DiscriminatorField('type')] #[DiscriminatorMap(['person' => Person::class, 'employee' => Employee::class])] class Person { // ... } #[Document] class Employee extends Person { // ... }
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

The discriminator value allows Doctrine to infer the class name to instantiate when hydrating a document. If a discriminator map is used, the discriminator value will be used to look up the class name in the map.

Now, if we query for a Person and its discriminator value is employee, we would get an Employee instance back:

1<?php $employee = new Employee(); // ... $dm->persist($employee); $dm->flush(); $employee = $dm->find(Person::class, $employee->getId()); // instanceof Employee
2
3
4
5
6
7
8

Even though we queried for a Person, Doctrine will know to return an Employee instance because of the discriminator map!

If your document structure has changed and you've added discriminators after already having a bunch of documents, you can specify a default value for the discriminator field:

1<?php namespace Documents; #[Document] #[InheritanceType('SINGLE_COLLECTION')] #[DiscriminatorField('type')] #[DiscriminatorMap(['person' => Person::class, 'employee' => Employee::class])] #[DefaultDiscriminatorValue('person')] class Person { // ... } #[Document] class Employee extends Person { // ... }
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

Collection Per Class Inheritance

With collection per class inheritance, each document is stored in its own collection and contains all inherited fields:

1<?php namespace Documents; #[Document] #[InheritanceType('COLLECTION_PER_CLASS')] class Person { // ... } #[Document] class Employee extends Person { // ... }
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

A discriminator is not needed with this type of inheritance since the data is separated in different collections.