Это лучшее решение, которое я придумал до сих пор, чтобы решить вышеуказанную проблему. Это не требует изменения кода JMSSerializer. Полный код находится в этом Gist: https://gist.github.com/Jaap-van-Hengstum/0d400ea4f986d8f8a044
Хитрость заключается в создании пустого «поддельного» класса:
namespace MyApp\ApiBundle\Serializer;
class SerializerProxyType
{
// this class is supposed to be empty
}
и в пользовательском DoctrineProxySubscriber
установите тип события для этого класса. Таким образом, JMSSerializer будет использовать этот тип для обработки аннотаций, поэтому он не запускает прокси-сервер Doctrine при обнаружении аннотаций, таких как @VirtualProperty
.
class DoctrineProxySubscriber implements EventSubscriberInterface
{
public function onPreSerialize(PreSerializeEvent $event)
{
$object = $event->getObject();
$type = $event->getType();
...
// This line is commented, so proxy loading on serializing is disabled
// $object->__load();
if ( ! $virtualType) {
// This line is commented because a different type is used
// $event->setType(get_parent_class($object));
// This assumes that every Doctrine entity has a single 'Id' primary
// key field.
$event->setType('MyApp\ApiBundle\Serializer\SerializerProxyType',
["id" => $object->getId()]);
}
}
public static function getSubscribedEvents()
{
return array(
array('event' => 'serializer.pre_serialize', 'method' => 'onPreSerialize'),
);
}
}
Затем вы можете использовать обработчик JMSSerializer, чтобы добавить собственный обработчик для пустого класса. Этот обработчик будет просто включать идентификатор объекта в сериализованный json/xml:
class DoctrineProxyHandler implements SubscribingHandlerInterface
{
/**
* {@inheritdoc}
*/
public static function getSubscribingMethods()
{
$methods = [];
foreach (array('json', 'xml') 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 serializeToXml(XmlSerializationVisitor $visitor, $entity, array $type, Context $context)
{
$visitor->getCurrentNode()->appendChild(
$node = $visitor->getDocument()->createElement('id', $type['params']['id'])
);
return $node;
}
}
Чтобы настроить Symfony для использования этих классов:
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 }
person
Jaap van Hengstum
schedule
12.01.2015