Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolving target entity in discriminator map omits fields from subtables #8402

Merged

Conversation

mpdude
Copy link
Contributor

@mpdude mpdude commented Dec 21, 2020

#1257 introduced the possibility to use interfaces instead of concrete classes also in the DiscriminatorMap. Here's an example config:

/** @DiscriminatorMap({"foo" = "FooInterface", "bar" = "BarConcreteImpl"}) */

The ResolveTargetEntityListener would be used to resolve such interface references to concrete classes at runtime.

The feature is currently broken. Core of the issue seems to be that \Doctrine\ORM\Mapping\ClassMetadataInfo::$subClasses is not populated with the concrete classes. This proably has to do with the resolution taking place too late, although I do not fully understand where this happens.

Example test failure before the change: https://github.com/doctrine/orm/pull/8402/checks?check_run_id=1587762816#step:7:73. The test case failed because the columns necessary for the subclasses are not created, but if they were (in an existing schema), the loaded entities would also lack data for their respective fields.

PR is against 2.7.x where the feature was introduced, since I did not find any documentation on PR policies/target branches.

@mpdude
Copy link
Contributor Author

mpdude commented Dec 21, 2020

Apparently, this might be fixed if the ResolveTargetEntityListener also deals with the DiscriminatorMap during the loadClassMetadata event.

@Ocramius:

You added this code in #1257. My guess is that, apart from the check that all classes are part of the DiscriminatorMap, it is no longer necessary when the ResolveTargetEntityListener deals with interface-to-class substitution: Since the concrete classes are now available much earlier, the discriminatorValue will already be setup correctly (happens in \Doctrine\ORM\Mapping\ClassMetadataInfo::addDiscriminatorMapClass()).

Maybe this method could even be removed altogether and the check added in \Doctrine\ORM\Mapping\ClassMetadataFactory::validateRuntimeMetadata()?

@mpdude
Copy link
Contributor Author

mpdude commented Dec 21, 2020

Note to self: #8378 might be working on the same thing/might be fixed as well by the last change? It's about the SchemaValidator.

@beberlei If from your work on #8378 (fixing #6578) you have additional insight on edge cases related to invalid Discriminator Map definitions, I'd be glad to hear from you!

@mpdude mpdude force-pushed the subtables-in-discripminator-interfaces branch from aa04876 to 2bfbe2b Compare December 21, 2020 10:27
beberlei
beberlei previously approved these changes Feb 5, 2021
Copy link
Member

@beberlei beberlei left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a valid bugfix, because the Events::loadClassMetadata is triggered inside AbstractClassMetadataFactory::loadMetadata and the logic from resolveDiscriminatorValue seems to be replaced correctly by the simple foreach in ResolveTargetEntityListener.

I am wondering though resolveDiscriminatorValue chanes $metadata->discrimintorValue, does this happen elsewhere now?

@beberlei
Copy link
Member

beberlei commented Feb 5, 2021

@mpdude needs to be rebased on 2.8.x as this is the bugfix target at the moment.

@mpdude mpdude force-pushed the subtables-in-discripminator-interfaces branch from 2bfbe2b to 0e19d61 Compare February 9, 2021 07:19
@mpdude mpdude changed the base branch from 2.7.x to 2.8.x February 9, 2021 07:19
@mpdude
Copy link
Contributor Author

mpdude commented Feb 9, 2021

Rebased to 2.8.x. The failing CS check applies to files not changed in this PR, so I'll ignore it.

@beberlei regarding your comment

I am wondering though resolveDiscriminatorValue chanes $metadata->discrimintorValue, does this happen elsewhere now?

I am not exactly sure what you're out for... The only write access to \Doctrine\ORM\Mapping\ClassMetadataInfo::$discriminatorValue I could find was in \Doctrine\ORM\Mapping\ClassMetadataInfo::addDiscriminatorMapClass().

My guess is that this will be called on every ClassMetadataInfo instance during metadata load, and that it will determine the discriminator value to be used for the underlying class (\Doctrine\ORM\Mapping\ClassMetadataInfo::$name).

Since the resolution of interfaces to concrete classes now happens before that, we should already be looking a the classes (not intefaces anymore) in this place... Not sure, does this answer your question?

@mpdude mpdude force-pushed the subtables-in-discripminator-interfaces branch from 0e19d61 to c59a214 Compare February 23, 2021 18:04
@mpdude
Copy link
Contributor Author

mpdude commented Feb 23, 2021

Rebased against 2.8.x again, hoping that this time this will resolve CS issues 🤞🏻

@mpdude mpdude force-pushed the subtables-in-discripminator-interfaces branch from a44dd97 to e57c3b7 Compare May 31, 2021 13:20
@mpdude mpdude force-pushed the subtables-in-discripminator-interfaces branch from 6e70a9f to ab1eefe Compare June 7, 2021 09:37
@mpdude mpdude changed the base branch from 2.8.x to 2.9.x June 7, 2021 09:37
@mpdude
Copy link
Contributor Author

mpdude commented Jun 7, 2021

@beberlei I've rebased this onto 2.9.x.

Given that you already had a look at this and basically agreed, could you please advise me what changes, clarifications or additional tests you'd like to see to make it a 👍?

@mpdude mpdude force-pushed the subtables-in-discripminator-interfaces branch from 7ad72e4 to ab1eefe Compare June 7, 2021 09:59
@mpdude
Copy link
Contributor Author

mpdude commented Jun 7, 2021

How can I make PHPStan/Psalm happy with regards to \Doctrine\ORM\Mapping\ClassMetadataFactory::validateRuntimeMetadata()?

The second argument $parent is hinted as ClassMetadataInterface, but I need to access $parent->discriminatorMap, which is not possible on an interface.

Changing it to ClassMetadata (as it is for the first $class argument) seems to be not easily possible because that in turn cascades to other, central places like \Doctrine\Persistence\Mapping\AbstractClassMetadataFactory::doLoadMetadata().

@greg0ire
Copy link
Member

greg0ire commented Jun 7, 2021

An easy way to fix this should be to use assert($parent instanceof ClassMetadata) if you are sure that's the case, and to create a Github issue to fix the introduced technical debt by handling that cascade you describe.

@mpdude
Copy link
Contributor Author

mpdude commented Jun 7, 2021

@greg0ire Thank you for the hint! I guess it makes only sense to open the other PR once this PR here is merged, right?

@greg0ire
Copy link
Member

greg0ire commented Jun 7, 2021

@greg0ire Thank you for the hint! I guess it makes only sense to open the other PR once this PR here is merged, right?

I think both issues and PR are independent, feel free to work on it now if you want to.

@greg0ire greg0ire added the Bug label Jun 15, 2021
@greg0ire greg0ire merged commit 7827869 into doctrine:2.9.x Jun 15, 2021
@greg0ire
Copy link
Member

Thanks @mpdude ! I took the liberty of squashing your commits, as most of them were amending the main one.

@mpdude
Copy link
Contributor Author

mpdude commented Jun 15, 2021

ORM 2.8 is end of life and this will not be backported, right?

@greg0ire
Copy link
Member

Correct 👍

@mpdude mpdude deleted the subtables-in-discripminator-interfaces branch June 15, 2021 11:02
@greg0ire greg0ire added this to the 2.9.4 milestone Aug 11, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants