0

This aremy 2 entitites

<?php

namespace App\Entity;

use App\Repository\CatalogRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass=CatalogRepository::class)
 */
class Catalog
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=255)
     */
    private $name;

    /**
     * @ORM\OneToMany(targetEntity=Title::class, mappedBy="Catalog", orphanRemoval=true)
     */
    private $titles;

    public function __construct()
    {
        $this->titles = new ArrayCollection();
    }

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getName(): ?string
    {
        return $this->name;
    }

    public function setName(string $name): self
    {
        $this->name = $name;

        return $this;
    }

    /**
     * @return Collection<int, Title>
     */
    public function getTitles(): Collection
    {
        return $this->titles;
    }

    public function addTitle(Title $title): self
    {
        if (!$this->titles->contains($title)) {
            $this->titles[] = $title;
            $title->setCatalog($this);
        }

        return $this;
    }

    public function removeTitle(Title $title): self
    {
        if ($this->titles->removeElement($title)) {
            // set the owning side to null (unless already changed)
            if ($title->getCatalog() === $this) {
                $title->setCatalog(null);
            }
        }

        return $this;
    }
}

and

<?php

namespace App\Entity;

use App\Repository\TitleRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass=TitleRepository::class)
 */
class Title
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=255)
     */
    private $title;

    /**
     * @ORM\Column(type="integer", nullable=true)
     */
    private $year;

    /**
     * @ORM\Column(type="float", nullable=true)
     */
    private $rating;

    /**
     * @ORM\ManyToOne(targetEntity=Catalog::class, inversedBy="titles")
     * @ORM\JoinColumn(nullable=false)
     */
    private $Catalog;

    public function __construct()
    {
        $this->Catalog = new ArrayCollection();
    }

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getTitle(): ?string
    {
        return $this->title;
    }

    public function setTitle(string $title): self
    {
        $this->title = $title;

        return $this;
    }

    public function getYear(): ?int
    {
        return $this->year;
    }

    public function setYear(?int $year): self
    {
        $this->year = $year;

        return $this;
    }

    public function getRating(): ?float
    {
        return $this->rating;
    }

    public function setRating(?float $rating): self
    {
        $this->rating = $rating;

        return $this;
    }

    public function getCatalog(): ?Catalog
    {
        return $this->Catalog;
    }

    public function setCatalog(?Catalog $Catalog): self
    {
        $this->Catalog = $Catalog;

        return $this;
    }
}

I when I try to seralize it

$em = $doctrine->getManager();
$catalogs = $em->getRepository(Catalog::class)->findAll();
       
$serializer = new Serializer(array(new GetSetMethodNormalizer()), array('json' => new 
JsonEncoder()));

$json = $serializer->serialize($catalogs, 'json', ['groups' => ['title','catalog']]);

I get this error

A circular reference has been detected when serializing the object of class "App\Entity\Catalog" (configured limit: 1).

Any way to avoid this problem??I know that catalor references title and totle recerences catalog but I think its the correct way to build the relation but it doesn't work for serialization, shoud I change shomething in the relation or I can serialize it in another way

UPDATE: I tried with ignore and groups but I get the same error

at catalog

/**
     * @ORM\Column(type="float")
     * @Groups({"group1"})
     */
    private $rating;

    /**
     * @ORM\ManyToOne(targetEntity=Catalog::class, inversedBy="titles")
     * @ORM\JoinColumn(nullable=false)
     * @Ignore()
     */
    private $Catalog;

and

 $json = $serializer->serialize($catalogs, 'json',  ['groups' => 'group1']);
af_fgh
  • 55
  • 3
  • Q: Where is the "circular reference" error occurring? In "Title" (not "Catalog"), correct? Q: Why do you need to declare a Collection in your Entity? Shouldn't a "Catalog" just be a collection of "Titles"? – paulsm4 May 30 '22 at 17:27
  • [This](https://stackoverflow.com/questions/71625324/symfony-serializer-circular-reference-due-to-many-to-many-relationship/71626984#71626984) might help you out, i posted answer a while ago.. – Bossman May 30 '22 at 20:47

1 Answers1

0

Sibling question here A circular reference has been detected when serializing the object of class "App\Entity\User" (configured limit: 1)

You can use the group concept as described in the official documentation

You can also create a circular reference handler to handle it. For exemple in your controller you can serialize the Catalog entity like :

<?php

namespace App\Controller;

use App\Repository\CatalogRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;

class MainController extends AbstractController
{
    #[Route('/', name: 'app_main')]
    public function index(CatalogRepository $catalogRepository, SerializerInterface $serializer): JsonResponse
    {
        $catalogs = $catalogRepository->findAll();

        $circularRefHandler = fn($catalog, $format, $context)=> $catalog->getName();

        $context = [
            AbstractNormalizer::CIRCULAR_REFERENCE_HANDLER => $circularRefHandler
        ];

        $catalogsJson = $serializer->serialize($catalogs, 'json', $context);


        return $this->json([
            'catalogs' => $catalogsJson
        ]);
    }
}


If you want tou use the GetSetMethodNormalizer create a context with GetSetMethodNormalizerContextBuilder

        $circularRefHandler = fn($catalog, $format, $context)=> $catalog->getName();

        $context = [
            AbstractNormalizer::CIRCULAR_REFERENCE_HANDLER => $circularRefHandler
        ];
       $contextBuilder = (new GetSetMethodNormalizerContextBuilder())
            ->withContext($context);

        $catalogsJson = $serializer->serialize($catalogs, 'json',$contextBuilder->toArray());

The full code of this example is here