避免使用Doctrine实体和JMSserializer进行递归

Way*_*neC 17 php symfony doctrine-orm fosuserbundle

我正在使用Symfony2,Doctrine,FOSRestBundle和JMSSerializer构建REST API.

我遇到的问题是在序列化我的实体时,序列化程序会引入任何相关实体.例如,对于作为董事会一部分的故事的一部分的任务,所以在序列化任务时,我得到的输出包括包含董事会的故事,其中包括董事会上的所有其他故事.

有没有一种简单的方法来限制它,只是包含foreignIds?

Mar*_*vić 19

使用JMS排除策略.

在类别实体上使用注释的示例,您不希望包含子项和要包含的产品相关实体:

use ...
    JMS\SerializerBundle\Annotation\ExclusionPolicy,
    JMS\SerializerBundle\Annotation\Exclude,
    ...;

/**
 * ...
 * @ExclusionPolicy("none")
 */
class Category
{
   /**
    * ...
    * @Exclude
    */
   private $children;

   /**
    * ...
    * @Exclude
    */
   private $products;

}
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请查看JMSSerializer文档.

编辑:

例如,您可以使用partial关键字仅选择所需的数据.虽然我不能,在我的生活中,如果我将实体对象传递给序列化器(即使在DoctrineProxyHandler中禁用加载),也禁用加载完整的相关实体(两个级别),但是如果我使用数组,那么不通过代理使用doctrine延迟加载(如预期的那样).

使用示例实体的示例:

$dql = "SELECT t, s, partial b.{id}, partial ss.{id}
        FROM Acme\AppBundle\Entity\Task t
        JOIN t.story s
        JOIN s.board b
        JOIN b.stories ss"

$q = $this->_em-createQuery($dql);

$result = $q->getArrayResult();
Run Code Online (Sandbox Code Playgroud)

这样你会得到类似的东西:

[
{
    id: 33,
    title: "My Task",
    story: [
    {
        id: 554,
        board: [
        {
            id: 14,
            stories: [
            {
                id: 554
            },
            {
                id: 3424
            },
            {
                id: 3487
            }
            ]
        }
        ]
    }
    ]

}
]
Run Code Online (Sandbox Code Playgroud)

PS我实际上对这个"问题"很感兴趣.无论如何,我会看到如何在不使用数组结果的情况下序列化实体对象的解决方案.

  • 友情更新:自[ver 0.11](https://github.com/schmittjoh/JMSSerializerBundle/blob/master/UPGRADING.md#upgrading-from-010-to-011)JMS Seralizer核心从包中提取出来, `JMS\SerializerBundle\Annotation\ExclusionPolicy`它将是`JMS\Serializer\Annotation\ExclusionPolicy`和`JMS\SerializerBundle\Annotation\Exclude`将是`JMS\Serializer\Annotation\Exclude`. (3认同)

Dav*_*Lin 9

只是最新版本的JMSSerializer的更新,你应该看看的地方

JMS \串行\此事件\用户\ DoctrineProxySubscriber

代替

串行\处理器\ DoctrineProxyHandler

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

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

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)

更新:我最后写的序列化工具的我自己的简化版本:https://github.com/dlin-me/array-converter-bundle


Kla*_* S. 8

检查JMSSerializerBundle上的Serializer/Handler/DoctrineProxyHandler.php文件.现在,如果你评论这一行:

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__) {
                //$data->__load();
            }
Run Code Online (Sandbox Code Playgroud)

它将停止延迟加载您的实体.如果这是你正在寻找的东西,那么继续创建你自己的处理程序,你不会延迟加载.

如果这不正确,我建议您根据自己的喜好自定义实体,然后再将它们发送到JMSSerializerBundle.例如,在我想要ID的任何相关实体中,而在其他实体中,我需要一个自定义列名,如代码,名称或任何东西.

我只是创建我的实体对象的副本,然后开始获取我需要的关系字段.然后,我序列化该副本.JMSSerializerBundle不会延迟加载,因为我已经提供了正确的字段.