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

Jam*_*ley 5 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似乎触发了所有相关实体的延迟加载,我似乎无法阻止它.我已经看到了一些链接,例如这个例子但是修复似乎不起作用(例如在该链接中,$object->__load()在原始代码中从未到达注释掉的调用.

我已经使用JMSSerializer的Group功能实现了一个基于关系的示例,但是当我理想情况下能够构建一个Doctrine Querybuilder实例,动态添加andWhere()调用并让序列化程序只返回那些确切的数据而不加载时,我觉得很奇怪.在人际关系中

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

cha*_*asr 1

您应该能够通过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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

当您的序列化结构良好时,您可以serializerGroups在控制器中动态设置 ,以便根据includefields参数(即/posts?fields[]=id&fields[]=title)使用不同的组。例子:

// PostController::getAction

use JMS\Serializer\SerializationContext;
use JMS\Serializer\SerializerBuilder;

$serializer = SerializerBuilder::create()->build();
$context = SerializationContext::create();
$groups = [];

// Assuming $request contains the "fields" param
$fields = $request->query->get('fields');

// Do this kind of check for all fields in $fields
if (in_array('foos', $fields)) {
    $groups[] = 'withFooAssociation';
}

// Tell the serializer to use the groups previously defined
$context->setGroups($groups);

// Serialize the data
$data = $serializer->serialize($posts, 'json', $context);

// Create the view
$view = View::create()->setData($data);

return $this->handleView($view);
Run Code Online (Sandbox Code Playgroud)

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

  • 请参阅“@MaxDepth”注释来限制关联的深度。如果您需要完全排除/公开某些字段,您肯定也需要为此处理组。如果您确实想使用自定义 QueryBuilder,则根本不使用序列化器,并将结果水合为数组(即 `$qb->getQuery->getArrayResult()`),您应该只获取由 select 添加的字段陈述。 (2认同)