Skip non-mapped typed properties with default values when using Proxies#2399
Skip non-mapped typed properties with default values when using Proxies#2399franmomu wants to merge 2 commits intodoctrine:2.10.xfrom
Conversation
adbcac6 to
c35fee8
Compare
| $oid = spl_object_hash($document); | ||
| if ($document instanceof GhostObjectInterface && ! $document->isProxyInitialized()) { | ||
| $document->setProxyInitializer(null); | ||
| $document->initializeProxy(); |
There was a problem hiding this comment.
This seems to do the trick, but we shouldn't initialize the object at this point as this will lead to a db query while we already have data waiting for hydration. The correct fix would be to somehow initialize properties not managed by the ODM
There was a problem hiding this comment.
Thanks @malarzm! that makes sense, I'll try to take a look how the ORM does this if I can. In the meantime I leave the test here just in case someone wants to give it a try
559e747 to
4a1a004
Compare
47540d6 to
b13ead6
Compare
|
I was taking a look again at this issue and one possible solution would be to skip these properties. I've skipped the typed non-mapped properties that have a default value. What about this? maybe is there something else to take into account? 🤔 |
|
@malarzm any chance that this might be merged? We are experiencing this issue with Doctrine 2.3 and were hoping to see it solved when we upgrade to 2.4 |
|
2.4 is already released. I'll take a look at this after the weekend for inclusion in a 2.5 patch release. |
b13ead6 to
b4b57e2
Compare
|
I made some adjustments to the tests to no longer rely on the absence of an error (and instead running an assertion), as well as applying the logic to all unmapped properties, not only those with default values. |
b4b57e2 to
f6cc0c1
Compare
| $customers = $this->dm->getRepository(GH2349Customer::class)->findAll(); | ||
|
|
||
| foreach ($customers as $customer) { | ||
| self::assertSame([], $customer->getEvents()); // This would trigger an error if unmapped properties are unset |
There was a problem hiding this comment.
This test seems fragile:
- we don't check whether
$customeris indeed a proxy - and is it still uninitialized (the test would still pass)
Maybe a db query count would be also good to assert so we never get into situation like the one found in original PR?
There was a problem hiding this comment.
Also i believe this would be better placed in a generic proxy test, where we don't even need database operations. Just creating a proxy and asserting whether unmapped stuff can be used without initialization - this should be easier to maintain in future
| private function skippedFieldsFqns(ClassMetadata $metadata): array | ||
| { | ||
| $skippedIdFieldsFqns = $this->getIdFieldsFqns($metadata); | ||
| $skippedNonMappedFieldsFqns = $this->getUnmappedPropertyFqns($metadata); |
There was a problem hiding this comment.
This looks more expensive than the original identifier exclusion and is called each and every time we create a proxy object, pretty much a hot path. We should memoize the result of skippedFieldsFqns per $metadata
| foreach ($reflectionClass->getProperties() as $property) { | ||
| $propertyName = $property->getName(); | ||
|
|
||
| if ($metadata->hasField($propertyName)) { |
There was a problem hiding this comment.
Just a note as field with different PHP and DB field always confused me: metadata is operating on PHP's object properties, and DB field name is used only in hydrators/persisters, right? If yes then we're A-OK here
| use Documents74\GH2349Customer; | ||
| use Documents74\GH2349Order; | ||
|
|
||
| /** @requires PHP 7.4 */ |
There was a problem hiding this comment.
If I'm seeing correctly, 7.4 was already minimal version for ODM 2.5.x :) No harm done given we haven't cleaned this up yet, worth doing before 2.6.x :)
Summary
Taking a look at #2349 seems like the problem is that the proxy is not initialized when it's managed.
Looking at the code, if the document is an instance ofGhostObjectInterfaceand it not initialized, it calls to$document->setProxyInitializer(null);which removes the initialization.To be honest I'm not sure if it's the right fix, maybe that code was there for some reason.
The test is from https://github.com/andythorne/doctrine-odm-example-error
Update: I was taking a look again to this issue, apparently one way to solve it is to skip those properties when using a proxy.