在 RESTAPI 中重新索引 ArrayCollection 元素

xur*_*d29 3 rest json arraycollection symfony

想象一下,我有一个数组集合$items,并removeItem在我的SomeEntity实体类中实现了一个方法,

public function removeItem(Item $item)
{
    $this->items->removeElement($item);
    return $this;
}
Run Code Online (Sandbox Code Playgroud)

以及接收 PATCH 请求的控制器操作:

public function patchAction(Request $request, SomeEntity $entity) {
    $form = ...;

    $form->handleRequest($request);
    if ($form->isValid()) {
        ...
        $this->get('doctrine.orm.entity_manager')->flush();

        return $entity;
    }

    return $form;
}
Run Code Online (Sandbox Code Playgroud)

想象一下,SomeEntity类的实例将项目保存为[0 => {ITEM}, 1 => {ITEM}, 2 => {ITEM}, 3 => {ITEM}](对象的索引数组)。如果您以 JSON 格式向前端项目中getActionSomeEntity对象发送请求并接收该对象,则对象中这些项目的类型将是对象的索引数组(您可以使用数组方法对其进行迭代),但是如果您删除一个或其中更多来自具有 PATCH 方法的对象并接收 JSON 响应,您将获得一个包含对象的 Object 类型,因为在 PATCH 请求之后某些键已被删除,并且响应中 SomeEntity 类的对象不再包含索引数组,而是会有一个对象的对象。这是因为,当您将数组转换为 json 对象时,您会得到两种不同的结果

  1. 对象数组(数组)如果键被索引(例如:0,1,2,3,...)
  2. 如果键没有索引(例如:0,2,3,6,...),则对象(数组)的对象

此时我正在通过修改(手动重新创建元素)removeItem实体类中的现有方法来解决这个问题,如下所示:

public function removeItem(Item $item)
{
    $this->items->removeElement($item);

    if (!$this->items->isEmpty()) {
        $items = new ArrayCollection();
        foreach ($this->items as $item) {
            $items->add($item);
        }

        $this->items = $items;
    }

    return $this;
}
Run Code Online (Sandbox Code Playgroud)

可能有更好的方法来解决这个问题?你怎么解决这个问题?

我正在使用 FOSRestBundle 和 JmsSerializerBundle。

Jas*_*man 6

这似乎是一个常见问题 -对于其他有此问题的人,请参阅https://github.com/schmittjoh/JMSSerializerBundle/issues/373。在删除项目的函数中,肯定有一种更短的方法来解决它,而不是再次循环遍历每个元素:

public function removeItem(Item $item)
{
    $this->items->removeElement($item);
    $this->items= new ArrayCollection($this->items->getValues());

    return $this;
}
Run Code Online (Sandbox Code Playgroud)

该票证中列出的其他解决方法可能适合也可能不适合您的需求 - 如果您想要一个全局解决方案,您可以覆盖强制转换为数组的 JsonSerializationVisitor类。