使用Symfony / FosRestBundle / JMS Serializer实现现场白名单的建议

时间:2016-03-25 00:37:42

标签: php symfony doctrine-orm jmsserializerbundle

我目前正在学习如何使用Symfony 3(带有FOSRestBundle)和JMS Serializer来实现相对简单的API。我最近一直在尝试实现作为消费客户端指定哪些字段应该在响应中返回的能力(请求的实体和关系中的两个字段)。例如;

    没有包含查询字符串的
  • /posts将返回所有Post实体属性(例如title,body,posted_at等),但无关系
  • /posts?fields[]=id&fields[]=title只返回帖子的ID和标题(但同样,没有关系
  • /posts?include[]=comment将包含以上内容,但Comment关系(及其所有属性)
  • /posts?include[]=comment&include[]=comment.author将如上所述返回,但也会在每条评论中包含作者

这是一个理智的尝试和实施?我最近对此进行了大量的研究,我看不出我可以1)限制单个字段的检索,2)只有在明确要求的情况下才返回相关实体。

我已经初步尝试了这个概念,但即使确保我的存储库只返回Post实体(即没有注释),JMS Serializer似乎触发了所有相关实体的延迟加载,我似乎无法停止这个。我已经看到了一些链接,例如this example但是这些修补程序似乎不起作用(例如在该链接中,在原始代码中从未到达注释掉的$object->__load()调用。

我已经实现了relationship-based example of this using JMSSerializer's Group functionality,但是当我理想情况下能够构建一个Doctrine Querybuilder实例,动态添加andWhere()调用并让序列化程序返回时,我感到很奇怪。精确数据,无需加载关系。

我为此撒谎而道歉,但我已经坚持了一段时间,我很感激任何投入!谢谢。

1 个答案:

答案 0 :(得分:2)

您应该能够通过Groups排除策略实现您想要的目标。

例如,您的Post实体可能如下所示:

use JMS\Serializer\Annotation as JMS;

/**
 * @JMS\ExclusionPolicy("all")
 */
class Post
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     * @ORM\Column(type="integer")
     *
     * @JMS\Expose
     * @JMS\Groups({"all", "withFooAssociation", "withoutAssociations"})   
     */
    private $id;

    /**
     * @ORM\Column(type="string")
     *
     * @JMS\Expose
     * @JMS\Groups({"all", "withFooAssociation", "withoutAssociations"})
     */
    private $title;

    /**
     * @JMS\Expose
     * @JMS\Groups({"all", "withFooAssociation"})
     *
     * @ORM\OneToMany(targetEntity="Foo", mappedBy="post")
     */
    private $foos;
}

像这样,如果您的控制器操作使用View返回serializerGroups={"all"},则响应将包含您实体的所有字段。

如果它使用serializerGroups={"withFooAssociation"},则回复将包含foos[]个关联条目及其公开字段。

并且,如果它使用serializerGroups={"withoutAssociation"},则foos关联将被序列化程序排除,因此不会呈现。

要从关联(Foo实体)的目标实体中排除属性,请在目标实体属性上使用相同的Groups以获得链式序列化策略。

当序列化结构良好时,您可以动态设置控制器中的serializerGroups,以便根据includefields参数使用不同的组(即{{1 }})。例如:

/posts?fields[]=id&fields[]=title

我希望我能正确理解你的问题,这足以帮助你。