Symfony 原则2:禁用延迟加载/代理生成。

Symfony 原则2:禁用延迟加载/代理生成。,symfony,doctrine-orm,doctrine,jmsserializerbundle,jms-serializer,Symfony,Doctrine Orm,Doctrine,Jmsserializerbundle,Jms Serializer,使用原则2,是否可以: 是否从生成的代理类中排除属性 完全禁用延迟加载/代理生成 我在序列化实体(使用Symfony和JMS序列化程序)时遇到问题。我只想序列化在查询中显式获取的关联实体 f.e.中描述的解决方案仅部分有效。当您拥有虚拟财产时: use Doctrine\ORM\Mapping as ORM; use JMS\Serializer\Annotation as Serializer; /** * Profile * * @ORM\Table(name="profile"

使用原则2,是否可以:

  • 是否从生成的代理类中排除属性
  • 完全禁用延迟加载/代理生成
我在序列化实体(使用Symfony和JMS序列化程序)时遇到问题。我只想序列化在查询中显式获取的关联实体

f.e.中描述的解决方案仅部分有效。当您拥有虚拟财产时:

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
中长期存在的错误。在生成代理/对象时,条令实际上做得相当不错。在一个实例中,我编辑了JMSSerializer源代码,以禁用从代理加载对象。我总是觉得那很烦人

可能的解决方法#1:在序列化之前设置
NULL
值。您将失去代理引用以供进一步使用,是的,它非常丑陋,但它确实起到了作用


可能的解决方法2:我可能错了,但我感觉JMSSerializer的开发已经停滞。您可以将项目分叉到您自己的GitHub,禁用执行抓取的行并使用您自己的分叉。

这是迄今为止我提出的解决上述问题的最佳解决方案。它不涉及更改JMSSerializer代码。完整代码见本要点:

诀窍是创建一个空的“假”类:

在自定义
doctrineproxy订阅者中,将事件类型设置为该类。这样,JMSSerializer将使用该类型进行注释处理,以便在遇到诸如
@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中包含实体的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 }

我认为条令应该有一个选项来禁用延迟加载(而不是即时加载)。依我看,ORM中的延迟加载是一种反模式/泄漏的抽象。无论如何,我提出了一个解决方案,它不涉及更改JMSSerializer代码。我不知道这是否是一种“官方”的方式,但对我来说似乎很有效。哇,所有这些都是因为一个错误,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 }