Last active
September 19, 2021 15:04
-
-
Save Jaap-van-Hengstum/0d400ea4f986d8f8a044 to your computer and use it in GitHub Desktop.
Disable lazy loading when serializing Doctrine 2 objects with JMS Serializer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
parameters: | |
jms_serializer.doctrine_proxy_subscriber.class: MyApp\ApiBundle\Serializer\DoctrineProxySubscriber | |
services: | |
doctrineproxy_handler: | |
class: MyApp\ApiBundle\Serializer\DoctrineProxyHandler | |
tags: | |
- { name: jms_serializer.subscribing_handler } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace MyApp\ApiBundle\Serializer; | |
use JMS\Serializer\Context; | |
use JMS\Serializer\GraphNavigator; | |
use JMS\Serializer\Handler\SubscribingHandlerInterface; | |
use JMS\Serializer\VisitorInterface; | |
use JMS\Serializer\XmlSerializationVisitor; | |
class DoctrineProxyHandler implements SubscribingHandlerInterface | |
{ | |
/** | |
* {@inheritdoc} | |
*/ | |
public static function getSubscribingMethods() | |
{ | |
$methods = []; | |
foreach (array('json', 'xml', 'yml') as $format) | |
{ | |
$methods[] = [ | |
'direction' => GraphNavigator::DIRECTION_SERIALIZATION, | |
'format' => $format, | |
'type' => 'MyApp\\ApiBundle\\Serializer\\SerializerProxyType', | |
'method' => 'serializeTo' . ucfirst($format), | |
]; | |
} | |
return $methods; | |
} | |
public function serializeToJson(VisitorInterface $visitor, $entity, array $type, Context $context) | |
{ | |
$object = new \stdClass(); | |
$object->id = $type['params']['id']; | |
return $object; | |
} | |
public function serializeToYml(VisitorInterface $visitor, $entity, array $type, Context $context) | |
{ | |
$object = new \stdClass(); | |
$object->id = $type['params']['id']; | |
return $object; | |
} | |
public function serializeToXml(XmlSerializationVisitor $visitor, $entity, array $type, Context $context) | |
{ | |
$visitor->getCurrentNode()->appendChild( | |
$formNode = $visitor->getDocument()->createElement('id', $type['params']['id']) | |
); | |
return $formNode; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace MyApp\ApiBundle\Serializer; | |
use Doctrine\ORM\PersistentCollection; | |
use Doctrine\Common\Persistence\Proxy; | |
use Doctrine\ORM\Proxy\Proxy as ORMProxy; | |
use JMS\Serializer\EventDispatcher\PreSerializeEvent; | |
use JMS\Serializer\EventDispatcher\EventSubscriberInterface; | |
class DoctrineProxySubscriber implements EventSubscriberInterface | |
{ | |
public function onPreSerialize(PreSerializeEvent $event) | |
{ | |
$object = $event->getObject(); | |
$type = $event->getType(); | |
// If the set type name is not an actual class, but a faked type for which a custom handler exists, we do not | |
// modify it with this subscriber. Also, we forgo autoloading here as an instance of this type is already created, | |
// so it must be loaded if its a real class. | |
$virtualType = ! class_exists($type['name'], false); | |
if ($object instanceof PersistentCollection | |
|| $object instanceof MongoDBPersistentCollection | |
|| $object instanceof PHPCRPersistentCollection | |
) { | |
if ( ! $virtualType) { | |
$event->setType('ArrayCollection'); | |
} | |
return; | |
} | |
if ( ! $object instanceof Proxy && ! $object instanceof ORMProxy) { | |
return; | |
} | |
//$object->__load(); | |
if ( ! $virtualType) { | |
//$event->setType(get_parent_class($object)); | |
$event->setType('MyApp\ApiBundle\Serializer\SerializerProxyType', | |
["id" => $object->getId()]); | |
} | |
} | |
public static function getSubscribedEvents() | |
{ | |
return array( | |
array('event' => 'serializer.pre_serialize', 'method' => 'onPreSerialize'), | |
); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace MyApp\ApiBundle\Serializer; | |
class SerializerProxyType | |
{ | |
// this class is supposed to be empty | |
} |
Yep I made a standalone library: https://github.com/alcalyn/serializer-doctrine-proxies
I set up everything as described but still cannot make it work…
I have a simple class Person(id, name, surname, addresses) with an array collection of addresses(id, street, city, person). During serialization the modified class DoctrineProxySubscriber is called with each Person object but only with them and not with separate Address classes. Addresses are then lazyloaded.
In controller I call:
$repo = $this->getDoctrine()->getRepository('AppBundle:Person\Person');
$person = $repo->search($term);
$serializer = $this->get('jms_serializer');
$data = $serializer->serialize($person, 'json');
Do you have any idea what can be wrong?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
anyone figured out on how to use this in a non-symfony framework?