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
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);
This will both convert the reference to a real object and fetch all the fields.
$entityManager->refresh($proxyObject);
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.
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:
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:
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;
}
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.