Symfony 4 & Doctrine 2 serialize after removing (first) item from collection causes converting to JSON object instead of array

故事扮演 提交于 2019-12-11 13:32:04

问题


I'm having a lot of trouble with serializing collection from which I've removed first element.

I have CompaniesCollection entity with Many2Many relation to Company entity.

/**
 * @ORM\ManyToMany(targetEntity="App\Entity\Company")
 * @Groups({"get-by-collection-owner"})
 */
private $items;

When I fetch the object with that collection, I receive items as an array of two elements I've added in the first place. I serialize it

{
    "id": 19,
    "name": "collection dummy name",
    "items": [
        {
            "id": 431,
            "name": "Company 1"
        },
        {
            "id": 435,
            "name": "Company 2"
        }
    ],
    "createdAt": "2019-03-11T13:55:43+01:00",
    "updatedAt": "2019-03-11T15:48:57+01:00"
},

Then I remove FIRST item:

    $collection->removeItem($companyToRemove);
    $em = $this->getDoctrine()->getManager();
    $em->persist($collection);
    $em->persist($companyToRemove);
    $em->flush();

    $results = $companiesCollectionRepository->getCollections($companyLoader->getCurrentCompany());

Serialize the $results and get not an array of one element, but object with key of second element from the previous array of items:

{
    "id": 19,
    "name": "collection dummy name",
    "items": {
        "1": {
            "id": 435,
            "name": "Company 2"
        }
    },
    "createdAt": "2019-03-11T13:55:43+01:00",
    "updatedAt": "2019-03-11T15:52:48+01:00"
},

When I reload the page and fetch this object, the collection is again one element array, not an object. Apparently Doctrine doesn't get new results from database, but returns data which has already loaded in the memory.

And serializer most likely treats this "array" as an "object", because it doesn't start with 0 for a key of first array element, but with key 1.

Is there any way to make that query again, so I get freshly generated keys, or refresh these keys?

EDIT:

Actually I've finally found simple solution for this: refresh after flush

    $collection->removeItem($companyToRemove);
    $em = $this->getDoctrine()->getManager();
    $em->persist($collection);
    $em->persist($companyToRemove);
    $em->flush();
    $em->refresh($collection);

回答1:


I've faced the same problem. And here is another solution which seems working for me.

Custom normalizer, which will be used for collections with "holes" in they keys:

namespace App\Serializer\Normalizer;

use Doctrine\Common\Collections\Collection;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Serializer\SerializerAwareInterface;
use Symfony\Component\Serializer\SerializerAwareTrait;

class DoctrineCollectionNormalizer implements NormalizerInterface, SerializerAwareInterface
{
    use SerializerAwareTrait;

    public function normalize($object, $format = null, array $context = array()): array
    {
        /* @var $object Collection */
        $values = $object->getValues();
        $object->clear();
        foreach ($values as $k => $value) {
            $object->set($k, $value);
        }

        return $this->serializer->normalize($object, $format, $context);
    }

    public function supportsNormalization($data, $format = null): bool
    {
        if ($data instanceof Collection) {
            $keys = $data->getKeys();
            $count = count($keys);
            $lastKey = (int) array_pop($keys);
            return $count && $lastKey !== $count-1;
        }
        return false;
    }
}


来源:https://stackoverflow.com/questions/55104868/symfony-4-doctrine-2-serialize-after-removing-first-item-from-collection-cau

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!