删除实体数组集合中的一项或多项时,Symfony 4.4 序列化程序问题

Symfony 4.4 serializer problem when one or more items from entity's array collection are removed

我注意到 Symfony 4.4 序列化器存在一个不寻常的问题,我将其用于其余控制器中的实体数据序列化 API。

在正常情况下,它工作正常但是如果我想序列化包含 属性 类型数组集合的实体并且我删除了一个数组集合项而不保存它输出数组集合的实体包含键 => 值对而不是对象数组的数组。

这是一个快速示例:

<?php

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Serializer\SerializerInterface;

use App\Entity\SomeEntity;

class BaseController extends AbstractController
{

/**
 * @Route("/test/{testEntityId}", methods={"GET"}, name="api.v1.test")
 */
public function getTestResult(string $testEntityId, SerializerInterface $serializer)
{
    $testEntityRepository = $this->getDoctrine()->getRepository(TestEntity::class);
    $testEntity = $this->testEntityRepository->findOneBy($testEntityId);

    // ## > The code in this scope messes up with the serializer
    if ($testEntity && $testEntity->hasSomeItems()) {
        $someItem = $testEntity->getSomeItems()->getFirst();
        $testEntity->removeSomeItem($someItem);
    }

    $serialized_data = $this->serializer->serialize($entity, 'json', ['groups' => ['test']]);

    $headers = ['Content-type' => 'application/json'];
    return new Response($serialized_data, 200, $headers);
}

}

这会 return

{ "someItems": [ "1": { someItem 02 object }, "2": { someItem 03 object }, etc. ] }

而不是

{ "someItems": [ { someItem 02 object }, { someItem 03 object }, etc. ] }

正常情况下。

发生这种情况是因为 removeSomeItem($someItem) 调用了 ArrayCollection 的 removeElement 方法,该方法删除了数组键为 0 的项目,而其余项目保持其键不变。

如果我在 Symfony 的 ArrayCollection removeElement 方法中强制执行以下行,我设法获得正常响应:$this->elements = array_values($this->elements); 以重置数组项键的顺序。

我需要一个解决方案来在控制器中解决这个问题,而不是更改 Symfony 的核心代码。使用实体管理器保存实体不适用,因为我只需要从数组集合中删除一些不兼容旧 API 客户端的项目以保持向后兼容性并且不想保留此类更改。

有什么好主意吗?

提前致谢!

我在 GitHub 上找到了一些相关的争论,并找到了在删除项目的实体方法中重新索引数组集合项目的解决方案:

<?PHP

namespace App\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use App\Entity\SomeItem;

class SomeEntity
{
    private $someItems;


    public function __construct()
    {
        parent::__construct();
        $this->someItems = new ArrayCollection();
    }

    public function removeSomeItem(SomeItem $someItem): self
    {
        if ($this->someItems->contains($someItem)) {
            $this->someItems->removeElement($someItem);

            // Reindex array elements to avoid problems with data serialization
            $this->someItems = new ArrayCollection($this->someItems->getValues());
        }

        return $this;
    }
}

这是一个众所周知的案例,如here所述。

诀窍是在 getter.

中使用 Collection::getValues()