From 3829232de0fd4cba5d79dda7c0e681a5f1278791 Mon Sep 17 00:00:00 2001 From: Matthias Pigulla Date: Thu, 19 Jan 2023 07:58:37 +0000 Subject: [PATCH 1/8] Review the documentation on inheritance --- docs/en/reference/inheritance-mapping.rst | 147 +++++++++++----------- 1 file changed, 76 insertions(+), 71 deletions(-) diff --git a/docs/en/reference/inheritance-mapping.rst b/docs/en/reference/inheritance-mapping.rst index 0c4c0c7050b..2eebabe1d00 100644 --- a/docs/en/reference/inheritance-mapping.rst +++ b/docs/en/reference/inheritance-mapping.rst @@ -1,6 +1,9 @@ Inheritance Mapping =================== +This chapter explains the available options for mapping class +hierarchies. + Mapped Superclasses ------------------- @@ -14,6 +17,10 @@ Mapped superclasses, just as regular, non-mapped classes, can appear in the middle of an otherwise mapped inheritance hierarchy (through Single Table Inheritance or Class Table Inheritance). +No database table will be created for a mapped superclasse itself, +only for entity classes inheriting from it. Also, a mapped superclass +need not have an ``#[Id]`` property. + .. note:: A mapped superclass cannot be an entity, it is not query-able and @@ -90,14 +97,46 @@ for the entity subclass. All the mappings from the mapped superclass were inherited to the subclass as if they had been defined on that class directly. +Entity Inheritance +------------------ + +As soon as one entity class inherits from another entity class, either +directly, with a mapped superclass or other unmapped (also called +"transient") classes in between, these entities form an inheritance +hierarchy. The topmost entity class in this hierarchy is called the +root entity, and the hierarchy includes all entities that are +descendants of this root entity. + +On the root entity class, ``#[InheritanceType]``, +``#[DiscriminatorColumn]`` and ``#[DiscriminatorMap]`` must be specified. + +``#[InheritanceType]`` specifies one of the two available inheritance +mapping strategies that are explained in the following sections. + +``#[DiscriminatorColumn]`` designates the so-called discriminator column. +This is an extra column in the database that keeps information about which +type from the hierarchy applies for a particular database row. + +``#[DiscriminatorMap]`` declares the possible values for the discriminator +column and maps them to class names in the hierarchy. This discriminator map +has to declare all non-abstract entity classes that exist in that particular +inheritance hierarchy. That includes the root as well as any intermediate +entity classes, given they are not abstract. + +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. + Single Table Inheritance ------------------------ `Single Table Inheritance `_ -is an inheritance mapping strategy where all classes of a hierarchy -are mapped to a single database table. In order to distinguish -which row represents which type in the hierarchy a so-called -discriminator column is used. +is an inheritance mapping strategy where all classes of a hierarchy are +mapped to a single database table. Example: @@ -162,27 +201,9 @@ Example: MyProject\Model\Employee: type: entity -Things to note: - - -- The ``#[InheritanceType]`` and ``#[DiscriminatorColumn]`` 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 a certain 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``. -- All entity classes that is part of the mapped entity hierarchy - (including the topmost class) should be specified in the - ``#[DiscriminatorMap]``. In the case above Person class included. -- 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. +In this example, the ``#[DiscriminatorMap]`` specifies that in the +discriminator column, a value of "person" identifies a row as being of type +``Person`` and employee" identifies a row as being of type ``Employee``. Design-time considerations ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -198,7 +219,7 @@ Performance impact This strategy is very efficient for querying across all types in the hierarchy or for specific types. No table joins are required, -only a WHERE clause listing the type identifiers. In particular, +only a ``WHERE`` clause listing the type identifiers. In particular, relationships involving types that employ this mapping strategy are very performing. @@ -206,8 +227,8 @@ There is a general performance consideration with Single Table Inheritance: If the target-entity of a many-to-one or one-to-one association is an STI entity, it is preferable for performance reasons that it be a leaf entity in the inheritance hierarchy, (ie. have no subclasses). -Otherwise Doctrine *CANNOT* create proxy instances -of this entity and will *ALWAYS* load the entity eagerly. +Otherwise Doctrine *cannot* create proxy instances +of this entity and will *always* load the entity eagerly. SQL Schema considerations ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -216,7 +237,7 @@ For Single-Table-Inheritance to work in scenarios where you are using either a legacy database schema or a self-written database schema you have to make sure that all columns that are not in the root entity but in any of the different sub-entities has to allow -null values. Columns that have NOT NULL constraints have to be on +null values. Columns that have ``NOT NULL`` constraints have to be on the root entity of the single-table inheritance hierarchy. Class Table Inheritance @@ -224,12 +245,13 @@ Class Table Inheritance `Class Table Inheritance `_ is an inheritance mapping strategy where each class in a hierarchy -is mapped to several tables: its own table and the tables of all +is mapped to several tables: Its own table and the tables of all parent classes. The table of a child class is linked to the table -of a parent class through a foreign key constraint. Doctrine ORM -implements this strategy through the use of a discriminator column -in the topmost table of the hierarchy because this is the easiest -way to achieve polymorphic queries with Class Table Inheritance. +of a parent class through a foreign key constraint. + +The discriminator column is placed in the topmost table of the hierarchy, +because this is the easiest way to achieve polymorphic queries with Class +Table Inheritance. Example: @@ -253,24 +275,9 @@ Example: // ... } -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. +As before, the ``#[DiscriminatorMap]`` specifies that in the +discriminator column, a value of "person" identifies a row as being of type +``Person`` and "employee" identifies a row as being of type ``Employee``. .. note:: @@ -301,7 +308,7 @@ perform just about any query which can have a negative impact on performance, especially with large tables and/or large hierarchies. When partial objects are allowed, either globally or on the specific query, then querying for any type will not cause the -tables of subtypes to be OUTER JOINed which can increase +tables of subtypes to be ``OUTER JOIN``ed which can increase performance but the resulting partial objects will not fully load themselves on access of any subtype fields, so accessing fields of subtypes after such a query is not safe. @@ -309,12 +316,12 @@ subtypes after such a query is not safe. There is a general performance consideration with Class Table Inheritance: If the target-entity of a many-to-one or one-to-one association is a CTI entity, it is preferable for performance reasons that it -be a leaf entity in the inheritance hierarchy, (ie. have no subclasses). -Otherwise Doctrine *CANNOT* create proxy instances -of this entity and will *ALWAYS* load the entity eagerly. +be a leaf entity in the inheritance hierarchy, ie. have no subclasses. +Otherwise Doctrine *cannot* create proxy instances +of this entity and will *always* load the entity eagerly. -There is also another important performance consideration that it is *NOT POSSIBLE* -to query for the base entity without any LEFT JOINs to the sub-types. +There is also another important performance consideration that it is *not possible* +to query for the base entity without any ``LEFT JOIN``s to the sub-types. SQL Schema considerations ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -332,14 +339,11 @@ column and cascading on delete. Overrides --------- -Used to override a mapping for an entity field or relationship. Can only be -applied to an entity that extends a mapped superclass or uses a trait to -override a relationship or field mapping defined by the mapped superclass or -trait. +Overrides can only be applied to entities that extend a mapped superclass or +use traits. They are used to override a mapping for an entity field or +relationship defined in that mapped superclass or trait. -It is not possible to override attributes or associations in entity to entity -inheritance scenarios, because this can cause unforseen edge case behavior and -increases complexity in ORM internal classes. +It is not supported to use overrides in entity inheritance scenarios. Association Override @@ -544,10 +548,11 @@ Example: Things to note: -- The "association override" specifies the overrides base on the property name. -- This feature is available for all kind of associations. (OneToOne, OneToMany, ManyToOne, ManyToMany) -- The association type *CANNOT* be changed. -- The override could redefine the joinTables or joinColumns depending on the association type. +- The "association override" specifies the overrides based on the property + name. +- This feature is available for all kind of associations (OneToOne, OneToMany, ManyToOne, ManyToMany). +- The association type *cannot* be changed. +- The override could redefine the ``joinTables`` or ``joinColumns`` depending on the association type. - The override could redefine ``inversedBy`` to reference more than one extended entity. - The override could redefine fetch to modify the fetch strategy of the extended entity. @@ -720,8 +725,8 @@ Could be used by an entity that extends a mapped superclass to override a field Things to note: -- The "attribute override" specifies the overrides base on the property name. -- The column type *CANNOT* be changed. If the column type is not equal you get a ``MappingException`` +- The "attribute override" specifies the overrides based on the property name. +- The column type *cannot* be changed. If the column type is not equal, you get a ``MappingException``. - The override can redefine all the attributes except the type. Query the Type From afca40b9b19e1f18d3ad9cc2867af1406c87f31e Mon Sep 17 00:00:00 2001 From: Matthias Pigulla Date: Thu, 19 Jan 2023 08:07:25 +0000 Subject: [PATCH 2/8] Add another warning regarding traits --- docs/en/reference/inheritance-mapping.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/en/reference/inheritance-mapping.rst b/docs/en/reference/inheritance-mapping.rst index 2eebabe1d00..38e70d3507a 100644 --- a/docs/en/reference/inheritance-mapping.rst +++ b/docs/en/reference/inheritance-mapping.rst @@ -345,6 +345,11 @@ relationship defined in that mapped superclass or trait. It is not supported to use overrides in entity inheritance scenarios. +.. note:: + + When using traits, make sure not to miss the warnings given in the + :doc:`Limitations and Known Issues` chapter. + Association Override ~~~~~~~~~~~~~~~~~~~~ From 096a59361dafc530ad16684729d007f6bc1b7c82 Mon Sep 17 00:00:00 2001 From: Matthias Pigulla Date: Thu, 19 Jan 2023 08:16:08 +0000 Subject: [PATCH 3/8] Add a note on auto-generating the DM --- docs/en/reference/inheritance-mapping.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/en/reference/inheritance-mapping.rst b/docs/en/reference/inheritance-mapping.rst index 38e70d3507a..11e3e03f17b 100644 --- a/docs/en/reference/inheritance-mapping.rst +++ b/docs/en/reference/inheritance-mapping.rst @@ -131,6 +131,15 @@ 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. +.. note:: + + Automatically generating the descriminator map is very expensive + computation-wise. The mapping driver has to provide all classes + for which mapping configuration exists, and those have to be + loaded and checked whether they are part of the current + inheritance hierarchy. The resulting map, however, can be kept + in the metadata cache. + Single Table Inheritance ------------------------ From 074df76745c75cfbf480940d99a33ea9ea1cad85 Mon Sep 17 00:00:00 2001 From: Matthias Pigulla Date: Thu, 19 Jan 2023 10:04:00 +0100 Subject: [PATCH 4/8] Update docs/en/reference/inheritance-mapping.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Grégoire Paris --- docs/en/reference/inheritance-mapping.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/reference/inheritance-mapping.rst b/docs/en/reference/inheritance-mapping.rst index 11e3e03f17b..35357b12731 100644 --- a/docs/en/reference/inheritance-mapping.rst +++ b/docs/en/reference/inheritance-mapping.rst @@ -17,7 +17,7 @@ Mapped superclasses, just as regular, non-mapped classes, can appear in the middle of an otherwise mapped inheritance hierarchy (through Single Table Inheritance or Class Table Inheritance). -No database table will be created for a mapped superclasse itself, +No database table will be created for a mapped superclass itself, only for entity classes inheriting from it. Also, a mapped superclass need not have an ``#[Id]`` property. From ed260d7fb0e05133144a267af2b9260d3fa8edc6 Mon Sep 17 00:00:00 2001 From: Matthias Pigulla Date: Thu, 19 Jan 2023 10:04:59 +0100 Subject: [PATCH 5/8] Update docs/en/reference/inheritance-mapping.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Grégoire Paris --- docs/en/reference/inheritance-mapping.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/reference/inheritance-mapping.rst b/docs/en/reference/inheritance-mapping.rst index 35357b12731..5c772fa08d9 100644 --- a/docs/en/reference/inheritance-mapping.rst +++ b/docs/en/reference/inheritance-mapping.rst @@ -114,7 +114,7 @@ On the root entity class, ``#[InheritanceType]``, mapping strategies that are explained in the following sections. ``#[DiscriminatorColumn]`` designates the so-called discriminator column. -This is an extra column in the database that keeps information about which +This is an extra column in the table that keeps information about which type from the hierarchy applies for a particular database row. ``#[DiscriminatorMap]`` declares the possible values for the discriminator From 25a141fe93ba69d71cf83a2703e5775d76b77868 Mon Sep 17 00:00:00 2001 From: Matthias Pigulla Date: Thu, 19 Jan 2023 10:05:09 +0100 Subject: [PATCH 6/8] Update docs/en/reference/inheritance-mapping.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Grégoire Paris --- docs/en/reference/inheritance-mapping.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/reference/inheritance-mapping.rst b/docs/en/reference/inheritance-mapping.rst index 5c772fa08d9..47bbdb02818 100644 --- a/docs/en/reference/inheritance-mapping.rst +++ b/docs/en/reference/inheritance-mapping.rst @@ -133,7 +133,7 @@ lowercase short name of each class as key. .. note:: - Automatically generating the descriminator map is very expensive + Automatically generating the discriminator map is very expensive computation-wise. The mapping driver has to provide all classes for which mapping configuration exists, and those have to be loaded and checked whether they are part of the current From 9acc37ebc070efd1f79f652820df5e124a91508b Mon Sep 17 00:00:00 2001 From: Matthias Pigulla Date: Thu, 19 Jan 2023 10:05:27 +0100 Subject: [PATCH 7/8] Update docs/en/reference/inheritance-mapping.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Grégoire Paris --- docs/en/reference/inheritance-mapping.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/reference/inheritance-mapping.rst b/docs/en/reference/inheritance-mapping.rst index 47bbdb02818..8ba2c2718f8 100644 --- a/docs/en/reference/inheritance-mapping.rst +++ b/docs/en/reference/inheritance-mapping.rst @@ -136,8 +136,8 @@ lowercase short name of each class as key. Automatically generating the discriminator map is very expensive computation-wise. The mapping driver has to provide all classes for which mapping configuration exists, and those have to be - loaded and checked whether they are part of the current - inheritance hierarchy. The resulting map, however, can be kept + loaded and checked against the current inheritance hierarchy + to see if they are part of it. The resulting map, however, can be kept in the metadata cache. Single Table Inheritance From 574ea7b4f90ae67793136f970d484387596b71ac Mon Sep 17 00:00:00 2001 From: Matthias Pigulla Date: Thu, 19 Jan 2023 09:06:31 +0000 Subject: [PATCH 8/8] Revert case change --- docs/en/reference/inheritance-mapping.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/reference/inheritance-mapping.rst b/docs/en/reference/inheritance-mapping.rst index 8ba2c2718f8..58cae459df9 100644 --- a/docs/en/reference/inheritance-mapping.rst +++ b/docs/en/reference/inheritance-mapping.rst @@ -254,7 +254,7 @@ Class Table Inheritance `Class Table Inheritance `_ is an inheritance mapping strategy where each class in a hierarchy -is mapped to several tables: Its own table and the tables of all +is mapped to several tables: its own table and the tables of all parent classes. The table of a child class is linked to the table of a parent class through a foreign key constraint.