mirror of
https://github.com/doctrine/orm.git
synced 2026-03-23 22:42:18 +01:00
[PR #10473] Allow to-many associations on mapped superclasses w/ ResolveTargetEntityListener #12391
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Original Pull Request: https://github.com/doctrine/orm/pull/10473
State: closed
Merged: Yes
Allow to-many associations to be used on mapped superclasses when the owning (inverse) side does not refer back to the mapped superclass, thanks to
ResolveTargetEntityListener.Current situation
The documentation states:
That's a though limitation.
ObviouslyapparentlyProbably the limitation comes from the fact that in a to-many association the "many" side has to hold a foreign key. Since the mapped superclass does not have a database table (it's not an entity), no such backreference can be established.Currently, to-many associations trigger an exception as soon as they are seen on a mapped superclass:
d6c0031d44/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php (L459-L461)ResolveTargetEntityListenerThe
ResolveTargetEntityListenercan be used to substitute interface or class names in mapping configuration at runtime, during the metadata load phase.When this gimmick is used to replace all references to the mapped superclass with an entity class in time, it should be possible to have to-many associations on the inheriting entity classes.
Suggested solution
Instead of rejecting to-many associations on mapped superclasses right away, validate that at the end of the day (after the
loadClassMetadataevent has been processed) no association may target at a non-entity class. That includes mapped superclasses as well as transient classes.Motivating example
Consider a library that comes with a
Userbase class. This class isabstractand has to be subclassed/filled when the library is used.By making this a mapped superclass, library users have the freedom to either have a simple user entity class or a user class hierarchy, but we do not impose any requirements on them. (NB we also don't want to have a root entity in the library, because that would have to declare the entire class hierarchy, including library users' classes.)
The actual user class to be used will be configured through the
ResolveTargetEntityListener.The library also includes a
SocialMediaAccountentity. AUsercan have multiple of these accounts, and we want to be able to navigate the accounts from the user side.To make the example even more fancy, there is a self-referencing association on the
User: AUserhas been created by another user, and holds a collection of all otherUsers it created.The test case contained in this PR contains this example and validates that all association mappings look just as if the final user class had been written as an entity directly, without the superclass.
Potential review talking points
targetEntitys that are not entities; relevant BC break? (IMHO: no.)Review tip
Review commit by commit, not all files at once. The last commit adds a lot of entity declarations that were previously missed in tests and now raised exceptions; that's a lot of clutter in the PR.
Relationship to #10455
This PR here does not make any changes to the inner workings of the ORM (!).
In fact, the example given can be run with current versions/releases of the ORM with no issues. That is possible because the one config validation rule that would stop it is in fact not effective, since the annotations/attribute mapping drivers do not report the potentially problematic association mapping in the first place.
This would change with #10455. Once that is merged, the to-many association would be dismissed right away and break the example.
So we need this PR here to keep examples like the one given working with #10455, by finding a more precise rule why/when to reject invalid configurations.
Other: This closes #10398, since the check no longer exists.