Skip to content

Instantly share code, notes, and snippets.

@Jaap-van-Hengstum
Last active September 19, 2021 15:04
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Jaap-van-Hengstum/0d400ea4f986d8f8a044 to your computer and use it in GitHub Desktop.
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
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 }
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;
}
}
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'),
);
}
}
namespace MyApp\ApiBundle\Serializer;
class SerializerProxyType
{
// this class is supposed to be empty
}
@tehabstract
Copy link

Nice work helped me a lot 👍

@photoup-godwinh
Copy link

anyone figured out on how to use this in a non-symfony framework?

@alcalyn
Copy link

alcalyn commented Mar 6, 2017

@Lukas871
Copy link

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