Closed ksowa closed 2 years ago
Sadly we can't fix this. With ODM 2.0 we decided to use https://github.com/Ocramius/ProxyManager instead of Doctrine's Proxy mechanism as what Marco wrote is way more powerful than our old solution. IIRC ORM also had plans to switch over to the new proxy mechanism which I guess would somehow fix your issue. But I don't know any details if and when ORM will do such a leap.
Offhand I'm not negating such approach worked but I do see a lot of things that could go wrong when passing uninitialized Proxies from other projects :D I'd advise to revisit this anyway.
Thank you @malarzm for clarifying the situation.
It's not about using uninitialized objects. Even if ORM initializes it, it's still going to be an instance of a proxy class.
It's not about using uninitialized objects. Even if ORM initializes it, it's still going to be an instance of a proxy class.
My comment was about using your approach in ODM 1.x :)
My approach didn't change - I use initialized objects, however since they are lazy-loaded, they are instances of proxy classes.
But it's irrelevant in case of this issue report. Thanks again for your help!
@malarzm I've done some more debugging and there's one thing which interested me. Maybe you would be able to explain the logic.
Let's take the same example as above - an instance of class Proxies\__CG__\App\Entity\User\Profile extends App\Entity\User\Profile
.
For an instance of the above class:
Doctrine\Persistence\Mapping\AbstractClassMetadataFactory::getMetadataFor()
with Proxies\__CG__\App\Entity\User\Profile
as the parameter. loadMetadata()
from the same class with the same param$this->getParentClasses($name)
) and tries to load their mappings in a loop (in the example it successfully loads mapping for App\Entity\User\Profile
)I'm wondering whether the idea behind that was to return parent's mapping in case of missing one for the given class. But I cannot tell that by just reading the code.
I'm not trying to complain about anything. I just thought I could help somehow with this piece of code.
To my knowledge, no. The idea is that we need parent's mapping to inherit everything that was defined there, take a look at ODM's ClassMetadataFactory: https://github.com/doctrine/mongodb-odm/blob/2.3.x/lib/Doctrine/ODM/MongoDB/Mapping/ClassMetadataFactory.php#L127.
To solve your issue you could try one of the following:
@malarzm yeah, I've already solved my issue by implementing the subscriber you mentioned in (1). And later I started wondering why ODM tries to load parent's class mappings. Looks like I didn't realize ODM does that to support Mapped Superclasses
feature.
Thank you again for the next part of clarifications!
Bug Report
Summary
After upgrading from ODM v1.x, I noticed there is a difference in naming of proxy classes between Doctrine ORM and ODM. This wasn't the case in the 1.x. It causes some unexpected behaviors when trying to store objects loaded from ORM to the ODM source.
Current behavior
Currently when I load an object via ORM, its lazy-loaded relations are instances of proxy classes, e.g.
Proxies\__CG__\App\Entity\User\Profile
. It uses the__CG__
as the namespace's part - it's defined inDoctrine\Persistence\Proxy::MARKER
.On the other hand ODM expects the marker to be
__PM__
, as perProxyManager\Inflector\ClassNameInflectorInterface::PROXY_MARKER
. Because of that ODM fails when trying to find a mappings for such objects.How to reproduce
Let's have two simple classes and assume their ORM and ODM mappings are correct:
When we properly load User instance from a DB and call
$profile = $user->getProfile()
, the$profile
is going to be an instance of something likeProxies\__CG__\App\Entity\User\Profile
.If we then try to store that to MongoDB via ODM, it's going to fail with an error message similar to below.
Example:
Error message:
The problem is caused by differences between these two places:
Doctrine\Persistence\Proxy::MARKER = '__CG__'
(used by ORM)ProxyManager\Inflector\ClassNameInflectorInterface::PROXY_MARKER = '__PM__'
(used by ODM)Expected behavior
I would expect that both ORM and ODM use the same proxy marker, like it was in version 1.x of ODM. In that version ODM was using the
Doctrine\Common\Util\ClassUtils::getRealClass()
method, which was used by ORM as well.