我目前正在学习如何使用Symfony 3(带FOSRestBundle)和JMS序列化程序实现一个相对简单的API。我最近一直在尝试实现作为消费客户端指定响应中应返回哪些字段(请求实体和关系中的字段)的功能。例如
- 不包含查询字符串的
/posts
将返回所有Post
实体属性(例如标题、正文、posted_at等),但没有关系 /posts?fields[]=id&fields[]=title
将只返回帖子的id和标题(但是,没有关系)/posts?include[]=comment
将包括上述内容,但具有Comment
关系(及其所有属性)/posts?include[]=comment&include[]=comment.author
将如上所述返回,但也会在每个评论中包含作者
这是一件明智的事情吗?我最近对此做了很多研究,我看不出我可以1)限制单个字段的检索,2)只在明确要求的情况下返回相关实体。
我已经对这个概念进行了一些初步的尝试,然而,即使在确保我的存储库只返回Post实体(即没有注释)时,JMS序列化程序似乎也会触发所有相关实体的延迟加载,我似乎无法阻止这一点。我看到了一些链接,比如这个例子,但修复似乎不起作用(例如,在那个链接中,注释掉的$object->__load()
调用在原始代码中永远无法到达
我已经使用JMSSerializer的Group
功能实现了一个基于关系的示例,但这样做感觉很奇怪,因为理想情况下,我可以构建一个Doctrine Querybuilder实例,动态添加andWhere()
调用,并让序列化程序只返回确切的数据,而不加载关系。
我很抱歉说得太多了,但我已经坚持了一段时间了,如果有任何意见,我将不胜感激!非常感谢。
您应该能够使用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;
}
像这样,如果控制器操作使用serializerGroups={"all"}
返回View
,则响应将包含实体的所有字段。
如果使用serializerGroups={"withFooAssociation"}
,则响应将包含foos[]
关联条目及其暴露的字段。
并且,如果它使用serializerGroups={"withoutAssociation"}
,则foos
关联将被序列化程序排除,因此它将不会被渲染。
要从关联的目标实体(Foo
实体)中排除属性,请对目标实体属性使用相同的Groups
,以获得链式序列化策略。
当您的序列化结构良好时,您可以在控制器中动态设置serializerGroups
,以便根据include
和fields
参数(即/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);
我希望我能正确理解你的问题,这足以帮助你。