使用JMS Serializer时禁用Doctrine 2延迟加载?

Chr*_*ber 15 php doctrine serializer jmsserializerbundle

我在我的Zend项目中使用Doctrine 2 ORM,并且需要在几种情况下将我的实体序列化为JSON.

ATM我使用Querybuilder并加入我需要的所有表.但是我的序列化程序导致学说延迟加载每个相关的实体,导致相当大的数据量并引发递归.

现在我正在寻找一种完全禁用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')
Run Code Online (Sandbox Code Playgroud)

我希望我的结果集只包含选定的表和关联.

任何帮助将不胜感激.

Dav*_*Lin 11

在最新版本的JMSSerializer中,您应该关注的地方是

JMS\Serializer\EventDispatcher\Subscriber\DoctrineProxySubscriber
Run Code Online (Sandbox Code Playgroud)

代替

Serializer\Handler\DoctrineProxyHandler
Run Code Online (Sandbox Code Playgroud)

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

在你的app/config.yml添加中:

parameters:
    ...
    jms_serializer.doctrine_proxy_subscriber.class: Your\Bundle\Event\DoctrineProxySubscriber
Run Code Online (Sandbox Code Playgroud)

你可以将类从JMS\Serializer\EventDispatcher\Subscriber\DoctrineProxySubscriber复制到你的\ 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));
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 谢谢.这很有帮助.但是仍在加载PersistentCollection对象.任何解决方案禁用此功能? (2认同)

Chr*_*ber 9

在Doctrine中寻找答案后,我的团队发现JMS Serializer是"问题".它自动触发了Doctrine Proxies的使用.我们编写了一个Patch for JMS Serializer以避免延迟加载.

我们实现了自己的DoctrineProxyHandler,它不会触发Doctrines延迟加载机制并在我们的SerializationHandlers数组中注册它.

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;
}
Run Code Online (Sandbox Code Playgroud)

现在我可以简单地选择我的表,加入我需要的关联 - 我的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')
Run Code Online (Sandbox Code Playgroud)

JSON将只包含

{  
  Personappointment: { table {fields}, company {fields}, appointment {fields}}
  Personappointment: { table {fields}, company {fields}, appointment {fields}}
  Personappointment: { table {fields}, company {fields}, appointment {fields}}
  .
  .
}
Run Code Online (Sandbox Code Playgroud)

  • 特别是在加载数据集合时(Doctrine\ORM\PersistentCollection). (2认同)