'Symfony6 FindBy and entity many to many

I use symfony6 for the first time with php 8.0.17. I want to make a small form that allows me to retrieve "Card" objects. My "Card" objects are bound to many to many color properties. I thought I could retrieve the cards objects via a findBy but I have the following error: Warning: Trying to access array offset on value of type null. I looked at the documentation but I don't understand where my error comes from.

Cannot use findBy with related object ? Or maybe it's not a good idea to use entity field in form ? As you see the code is simple and it's that i don't understand it's not okay

The code is here :

My Card entity :

<?php

namespace App\Entity;

use App\Repository\CardRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

#[ORM\Entity(repositoryClass: CardRepository::class)]
class Card
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    private $id;

    #[ORM\ManyToMany(targetEntity: Color::class, inversedBy: 'card')]
    private $color;

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

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

    /**
     * @return Collection<int, Color>
     */
    public function getColor(): Collection
    {
        return $this->color;
    }

    public function addColor(Color $color): self
    {
        if (!$this->color->contains($color)) {
            $this->color[] = $color;
        }

        return $this;
    }

    public function removeColor(Color $color): self
    {
        $this->color->removeElement($color);

        return $this;
    }
}

My Color entity :


<?php

namespace App\Entity;

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

#[ORM\Entity(repositoryClass: ColorRepository::class)]
class Color
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    private $id;

    #[ORM\Column(type: 'string', length: 255)]
    private $name;

    #[ORM\ManyToMany(targetEntity: Card::class, mappedBy: 'color')]
    private $card;

    public function __construct()
    {
        $this->card = 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;
    }

    public function __toString()
    {
        return $this->getName();
    }

    /**
     * @return Collection<int, Card>
     */
    public function getCard(): Collection
    {
        return $this->card;
    }

    public function addCard(Cards $card): self
    {
        if (!$this->card->contains($card)) {
            $this->card[] = $card;
            $card->addColor($this);
        }

        return $this;
    }

    public function removeCard(Cards $card): self
    {
        if ($this->cards->removeElement($card)) {
            $card->removeColor($this);
        }

        return $this;
    }
}

My Search Form :

<?php

namespace App\Form;

use App\Entity\Color;
use App\Entity\Keyword;
use App\Entity\Type;
use App\Form\DataTransformer\ColorToStringTransformer;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;

class CardSearchType extends AbstractType
{
    
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('name', TextType::class, ['required' => false])
            ->add('color', EntityType::class, [
                'class' => Color::class,
                // uses the Cards.name property as the visible option string
                'choice_label' => 'name',
                // used to render a select box, check boxes or radios
                // 'multiple' => true,
                // 'expanded' => true,
                // To add little test for empty value
                'placeholder' => 'Choose a color.',
                'required' => false,
            ])
            ->add('save', SubmitType::class)
        ;
    }

    public function configureOptions(OptionsResolver $resolver): void
    {

    }
}

And to finish the controller action :

class DeckBuilderController extends AbstractController
{
    #[Route('/deck/builder', name: 'app_deck_builder')]
    public function index(Request $request, CardRepository $cardRepository): Response
    {
        $form = $this->createForm(CardSearchType::class);
        $form->handleRequest($request);
        $cards = null;
        if ($form->isSubmitted() && $form->isValid())
        {
            // $form->getData() holds the submitted values
            $cardData = $form->getData();
            $cards = $cardRepository->findBy($cardData); => error Warning: Trying to access array offset on value of type null
            
        }
        return $this->render('deck_builder/index.html.twig', [
            'controller_name' => 'DeckBuilderController',
            'form' => $form->createView(),
            'cards' => $cards,
        ]);
    }

Thank in advance for your response.



Solution 1:[1]

$form->getData() doesn't return an array but an object with the form content. My guess is that you want to use $form->get('color')->getData() instead

Correcting your code, I would try something like this :

public function index(Request $request, CardRepository $cardRepository): Response {
    $cards = array();
    $form = $this->createForm(CardSearchType::class);
    $form->handleRequest($request);

    if($form->isSubmitted() && $form->isValid()) {
        $cards = $cardRepository->findBy(array('color'=>$form->get('color')->getData()));
    }

    return $this->renderForm('deck_builder/index.html.twig', array(
        'controller_name' => 'DeckBuilderController',
        'form' => $form,
        'cards' => $cards,
    ));
}

Solution 2:[2]

To solve my problem I finally created a query by hand and made the join in DQL.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 k.gonzalez