使用原则 2,是否可以:
我在序列化我的实体时遇到问题(使用 Symfony 和 JMS Serializer)。我只想序列化在查询中显式获取的关联实体。
f.e.中描述的解决方案使用 JMS Serializer 时禁用 Doctrine 2 延迟加载? 仅部分有效。当您拥有虚拟财产时:
use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as Serializer;
/**
* Profile
*
* @ORM\Table(name="profile")
* @ORM\Entity
*/
class Profile
{
// ...
/**
* @return string
*
* @Serializer\VirtualProperty()
*/
public function getLabel()
{
return implode(' ', [$this->firstname, $this->lastname]) . " ({$this->email})";
}
}
序列化过程中仍然通过代理加载关联的类。
这是我迄今为止为解决上述问题想出的最好的解决方案。它不涉及更改 JMSSerializer 代码。完整代码在此要点中: https://gist.github.com/Riley-van-Hengstum/0d400ea4f986d8f8a044
诀窍是创建一个空的“假”类:
namespace MyApp\ApiBundle\Serializer;
class SerializerProxyType
{
// this class is supposed to be empty
}
并在自定义
DoctrineProxySubscriber
中,将事件类型设置为该类。这样 JMSSerializer 将使用该类型进行注释处理,因此在遇到像 @VirtualProperty
这样的注释时不会触发 Doctrine 代理。
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 中包含实体的 ID:
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 }
我认为这是
JMSSerializer
中长期存在的错误。实际上,Doctrine 在生成代理/对象时做得相当不错。在一个实例中,我编辑了 JMSSerializer 源代码以禁用从代理加载对象。我总是觉得这真的很烦人。
可能的解决方法#1:在序列化之前设置
NULL
值。您将失去代理参考以供进一步使用,是的,它非常丑陋,但它可以完成工作。
可能的解决方法#2:我可能是错的,但我感觉 JMSSerializer 的开发已经停滞。您可以将项目分叉到您自己的 GitHub,禁用执行获取的行并使用您自己的分叉。