简体   繁体   English

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

[英]Advice for implementing field whitelists with Symfony/FosRestBundle/JMS Serializer

I'm currently learning how to implement a relatively simple API using Symfony 3 (with FOSRestBundle) and JMS Serializer. 我目前正在学习如何使用Symfony 3(带有FOSRestBundle)和JMS Serializer来实现一个相对简单的API。 I've been trying recently to implement the ability to specify, as a consuming client, which fields should be returned within a response (both fields within the requested entity and relationships). 我最近一直在尝试实现作为消费客户端指定哪些字段应该在响应中返回的能力(请求的实体和关系中的两个字段)。 For example; 例如;

  • /posts with no include query string would return all Post entity properties (eg title, body, posted_at etc) but no relationships . /posts没有包含查询字符串的Post将返回所有Post实体属性(例如title,body,posted_at等)但没有关系
  • /posts?fields[]=id&fields[]=title would return only the id and title for posts (but again, no relationships ) /posts?fields[]=id&fields[]=title将仅返回帖子的ID和标题(但同样没有关系
  • /posts?include[]=comment would include the above but with the Comment relationship (and all of its properties) /posts?include[]=comment将包含上述但与Comment关系(及其所有属性)
  • /posts?include[]=comment&include[]=comment.author would return as above, but also include the author within each comment /posts?include[]=comment&include[]=comment.author将如上所述返回,但也包括每个评论中的作者

Is this a sane thing to try and implement? 尝试实施这是一个明智的事情吗? I've been doing quite a lot of research on this recently and I can't see I can 1) restrict the retrieval of individual fields and 2) only return related entities if they have been explicitly asked for. 我最近对此进行了大量的研究,我看不出我可以1)限制单个字段的检索,2)只有在明确要求的情况下才返回相关实体。

I have had some initial plays with this concept, however even when ensuring that my repository only returns the Post entity (ie no comments), JMS Serializer seems to trigger the lazy loading of all related entities and I can't seem to stop this. 我已经有了这个概念的初步播放,但是即使确保我的存储库只返回Post实体(即没有注释),JMS Serializer似乎触发了所有相关实体的延迟加载,我似乎无法阻止它。 I have seen a few links such as this example however the fixes don't seem to work (for example in that link, the commented out $object->__load() call is never reached anyway in the original code. 我已经看到了一些链接,例如这个例子但是修复似乎不起作用(例如在该链接中,在原始代码中从未到达注释掉的$object->__load()调用。

I have implemented a relationship-based example of this using JMSSerializer's Group functionality but it feels weird having to do this, when I would ideally be able to build up a Doctrine Querybuilder instance, dynamically adding andWhere() calls and have the serializer just return that exact data without loading in relationships. 我已经使用JMSSerializer的Group功能实现了一个基于关系的示例,但是当我理想情况下能够构建一个Doctrine Querybuilder实例,动态添加andWhere()调用并让序列化器返回时,我觉得很奇怪。精确数据,无需加载关系。

I apologise for rambling with this but I've been stuck with this for some time, and I'd appreciate any input! 我为此撒谎而道歉,但我已经坚持了一段时间,我很感激任何输入! Thank you. 谢谢。

You should be able to achieve what you want with the Groups exclusion strategy. 您应该能够通过Groups排除策略实现您想要的目标。

For example, your Post entity could look like this: 例如,您的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;
}

Like this, if your controller action returns a View using serializerGroups={"all"} , the Response will contains all fields of your entity. 像这样,如果您的控制器操作使用serializerGroups={"all"}返回View ,则Response将包含您实体的所有字段。

If it uses serializerGroups={"withFooAssociation"} , the response will contains the foos[] association entries and their exposed fields. 如果它使用serializerGroups={"withFooAssociation"} ,则响应将包含foos[]关联条目及其公开的字段。

And, if it uses serializerGroups={"withoutAssociation"} , the foos association will be excluded by the serializer, and so it will not be rendered. 并且,如果它使用serializerGroups={"withoutAssociation"} ,则foos关联将被序列化程序排除,因此它将不会被渲染。

To exclude properties from the target entity of the association ( Foo entity), use the same Groups on the target entity properties in order to get a chained serialisation strategy. 要从关联的目标实体( Foo实体)中排除属性,请在目标实体属性上使用相同的Groups ,以获得链式序列化策略。

When your serialization structure is good, you can dynamically set the serializerGroups in your controller, in order to use different groups depending on the include and fields params (ie /posts?fields[]=id&fields[]=title ). 当您的序列化结构良好时,您可以在控制器中动态设置serializerGroups ,以便根据includefields params使用不同的组(即/posts?fields[]=id&fields[]=title )。 Example: 例:

// 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);

I hope that I correctly understood your question and that this will be sufficient for help you. 我希望我正确理解你的问题,这将足以帮助你。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM