在使用 JMS 序列化程序时禁用原则 2 延迟加载?

我在我的Zend项目中使用Therism 2 ORM,并且需要在某些情况下将我的实体序列化为JSON。

ATM我使用查询构建器并加入我需要的所有表。但是我的序列化程序导致原则延迟加载每个关联的实体,这会导致相当大的数据量并引发递归。

现在我正在寻找一种方法来完全禁用 Doctrines 延迟加载行为。

我选择数据的方法如下:

$qb= $this->_em->createQueryBuilder()
            ->from("\Project\Entity\Personappointment", 'pa')
            ->select('pa', 't', 'c', 'a', 'aps', 'apt', 'p')
            ->leftjoin('pa.table', 't')
            ->leftjoin('pa.company', 'c')
            ->leftjoin('pa.appointment', 'a')
            ->leftjoin('a.appointmentstatus', 'aps')
            ->leftjoin('a.appointmenttype', 'apt')
            ->leftjoin('a.person','p')

我希望我的结果集仅包含选定的表和关联。

任何帮助将不胜感激。


答案 1

在最新版本的 JMSSerializer 中,您应该查看的位置是

JMS\Serializer\EventDispatcher\Subscriber\DoctrineProxySubscriber

而不是

Serializer\Handler\DoctrineProxyHandler

要覆盖默认的延迟加载行为,应该定义自己的事件订阅者。

在你的添加这个:app/config.yml

parameters:
    ...
    jms_serializer.doctrine_proxy_subscriber.class: Your\Bundle\Event\DoctrineProxySubscriber

您可以将类从 JMS\Serializer\EventDispatcher\Subscriber\DoctrineProxySubscriber 复制到 Your\Bundle\Event\DoctrineProxySubscriber 并注释掉$object->__load();线

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) {
        if ( ! $virtualType) {
            $event->setType('ArrayCollection');
        }

        return;
    }

    if ( ! $object instanceof Proxy && ! $object instanceof ORMProxy) {
        return;
    }

     //$object->__load(); Just comment this out

    if ( ! $virtualType) {
        $event->setType(get_parent_class($object));
    }
}

答案 2

在 Doctrine 中寻找答案后,我的团队发现 JMS 序列化程序是“问题”。它自动触发了教义代理的使用。我们为 JMS 序列化程序编写了一个补丁,以避免延迟加载。

我们实现了自己的 DoctrineProxyHandler,它只是不触发 Doctrines lazyloading 机制,并将其注册到我们的序列化Handlers Array 中。

class DoctrineProxyHandler implements SerializationHandlerInterface {

public function serialize(VisitorInterface $visitor, $data, $type, &$handled)
{
    if (($data instanceof Proxy || $data instanceof ORMProxy) && (!$data->__isInitialized__ || get_class($data) === $type)) {
        $handled = true;

        if (!$data->__isInitialized__) {

            //don't trigger doctrine lazy loading
            //$data->__load();

            return null;
        }

        $navigator = $visitor->getNavigator();
        $navigator->detachObject($data);

        // pass the parent class not to load the metadata for the proxy class
        return $navigator->accept($data, get_parent_class($data), $visitor);
    }

    return null;
}

现在我可以简单地选择我的表,加入我需要的关联 - 我的JSON将只包含我选择的数据,而不是无限深度关联和递归:)

$qb= $this->_em->createQueryBuilder()
        ->from("\Project\Entity\Personappointment", 'pa')
        ->select('pa', 't', 'c', 'a')
        ->leftjoin('pa.table', 't')
        ->leftjoin('pa.company', 'c')
        ->leftjoin('pa.appointment', 'a')

JSON 将只包含

{  
  Personappointment: { table {fields}, company {fields}, appointment {fields}}
  Personappointment: { table {fields}, company {fields}, appointment {fields}}
  Personappointment: { table {fields}, company {fields}, appointment {fields}}
  .
  .
}

推荐