Getting a “true” object from a proxy object in doctrine2

前端 未结 11 1430
南笙
南笙 2021-02-01 13:50

Doctrine uses proxy objects to represent related objects in order to facilitate lazy loading. This is a really cool feature, but its causing an issue with something I am trying

相关标签:
11条回答
  • 2021-02-01 14:43

    Doctrines lazy loading is very good at its job, and will replace a proxy object with a real one as soon as you try to use it or any of its properties. If you are having issues due to the proxy objects (like I did in my question) you most probably have an error in your model.

    That said, you can tell doctrine to pull all the related data by telling it to "hydrate": $query->getResult(Doctrine\ORM\Query::HYDRATE_ARRAY);

    0 讨论(0)
  • 2021-02-01 14:43

    This will both convert the reference to a real object and fetch all the fields.

    $entityManager->refresh($proxyObject);
    
    0 讨论(0)
  • 2021-02-01 14:49

    This is unlikely to help in the specific instance for the question, since you're relying on a third-party module, but you can prevent the lazy loading by setting the "fetch mode" for your entity to "EAGER".

    User:
        ManyToOne:
            city:
                fetch: EAGER
    

    This can also be handled by annotations:

    @ManyToOne(targetEntity="city", fetch="EAGER")
    @JoinColumn(name="city", referencedColumnName="id")
    

    See http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/annotations-reference.html#annref-manytoone

    None of the other answers I've seen here worked for me.

    0 讨论(0)
  • 2021-02-01 14:49

    You get an unique instance of an entity from Doctrine. If you request it two times, you'll always get the same object.

    As a consequence, if your entity is lazy-loaded first (via a @ManyToOne somewhere for example), this entity instance will be a Proxy.

    Example:

    You have a User entity having a bidirectional @OneToOne on a Config entity...

    Case 1

    You request your User:

    • you get a real instance of User
    • $user->config will contain a Proxy

    If later on you request the same Config entity in any piece of your app, you'll end up with that proxy.

    Case 2

    You request your Config and your User has never been imported before:

    • you get a real instance of Config
    • $config->user will contain a Proxy

    If later on you request the same User entity in any piece of your app, you'll end up with that proxy.


    All in all, querying again for the same entity will still end up to a proxy (which is an instance of your User anyway, because the generated proxy extends from it).

    If you really need a second instance of your entity that is a real one (if some of your app logic does a get_class that you can't replace by instanceof for example), you can try to play with $em->detach() but it will be a nightmare (and thus your app may behave with even more magic than Doctrine already bring).

    A solution (coming from my dark side, I assume) can be recreating a non-managed Entity manually.

    public function getRealEntity($proxy)
    {
        if ($proxy instanceof Doctrine\ORM\Proxy\Proxy) {
            $metadata              = $this->getManager()->getMetadataFactory()->getMetadataFor(get_class($proxy));
            $class                 = $metadata->getName();
            $entity                = new $class();
            $reflectionSourceClass = new \ReflectionClass($proxy);
            $reflectionTargetClass = new \ReflectionClass($entity);
            foreach ($metadata->getFieldNames() as $fieldName) {
                $reflectionPropertySource = $reflectionSourceClass->getProperty($fieldName);
                $reflectionPropertySource->setAccessible(true);
                $reflectionPropertyTarget = $reflectionTargetClass->getProperty($fieldName);
                $reflectionPropertyTarget->setAccessible(true);
                $reflectionPropertyTarget->setValue($entity, $reflectionPropertySource->getValue($proxy));
            }
    
            return $entity;
        }
    
        return $proxy;
    }
    
    0 讨论(0)
  • 2021-02-01 14:49

    The solution I found is to extend the Reflection Hydrator and use the new class as Hal extractor params, for complex entities.

    You can find the code here:

    Synergy of proxy object of doctrine and zend expressive hal

    probably.

    0 讨论(0)
提交回复
热议问题