EasyAdminBundle icon indicating copy to clipboard operation
EasyAdminBundle copied to clipboard

ChoiceFilter not working with ChoiceField allowing multiple

Open mhbailly opened this issue 2 months ago • 6 comments

Describe the bug ChoiceFilter does not work to search for multiple values in a ChoiceField that allows multiple values.

To Reproduce

  • Create an array field on an entity
#[ORM\Column(nullable: true)]
private ?array $testField = null;
  • Create a ChoiceField in the corresponding Crud Controller with the allowMultipleChoices modifier
yield ChoiceField::new('testField')
        ->allowMultipleChoices()
        ->setTranslatableChoices($this->getOptions());

with in the controller

public function getOptions()
{
    return [
        'CA' => 'Canada',
        'US' => 'United States of America',
        'BE' => 'Belgique',
     ];
}
  • Add a ChoiceFilter with the canSelectMultiple modifier
public function configureFilters(Filters $filters): Filters
{
    return parent::configureFilters($filters)
        ->add(ChoiceFilter::new('testField')->setTranslatableChoices($this-> getOptions())->canSelectMultiple());
}

  • Create some test records with testField = CA
  • Try to filter the index page with testField = CA --> should get 0 result
  • The executed query contains a WHERE clause similar to testField IN ("CA") . Because testField is a json column in the database (MySQL), this does not work.

Additional context

Image Image

mhbailly avatar Oct 14 '25 04:10 mhbailly

Hello @mhbailly,

If your "testField" represents a set of fixed values such as countries, tags, or categories, it’s better to normalize the database schema using an entity relation instead of a JSON array.

For example:

src/Entity/Country.php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
class Country
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 50, unique: true)]
    private ?string $code = null;

    #[ORM\Column(length: 100)]
    private ?string $name = null;

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

Then modify your "BlogArticle" entity:

#[ORM\ManyToMany(targetEntity: Country::class, cascade: ['persist'])]
private Collection $countries;

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

public function getCountries(): Collection
{
    return $this->countries;
}

And update your CRUD controller:

use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;

yield AssociationField::new('countries')
    ->setFormTypeOptions(['by_reference' => false])
    ->setRequired(false);

And filters:

use EasyCorp\Bundle\EasyAdminBundle\Filter\EntityFilter;

$filters->add(EntityFilter::new('countries'));
Image

pbaumes avatar Nov 09 '25 20:11 pbaumes

Thanks for looking at this @pbaumes However, I don't see

->allowMultipleChoices() in your configureFields method nor ->canSelectMultiple()) in the configureFilters method

I don't think that using an Entity is the issue in this case but I might be wrong. With your proposed change, I would need yet another table to save the many-to-many relationship.

mhbailly avatar Nov 09 '25 21:11 mhbailly

@mhbailly , in fact, the multiple choices is induced by the “ManyToMany” relationship itself. In my screenshot, you can see that the type is a multiple choice. I could have added "Canada" in addition to “France.” =>

Image

pbaumes avatar Nov 09 '25 21:11 pbaumes

Thanks @pbaumes, appreciate it. I missed the #[ORM\ManyToMany() It's definitely a viable workaround and going to use it but I still think this is a bug or at least should be known as a limitation / know issue

mhbailly avatar Nov 09 '25 21:11 mhbailly

Hi @mhbailly ,

After looking into your problem in more detail, I have found a solution for your configuration. You can ignore my previous messages and use the “ArrayFilter” instead of “ChoiceFilter” as follows:

    public function configureFilters(Filters $filters): Filters
    {
        $filters
            ->add(EntityFilter::new('category'))
            ->add(ArrayFilter::new('testField')->setTranslatableChoices($this-> getOptions())->canSelectMultiple());

        return $filters;
    }

...which should give you the following result:

Image

the query will be as follows:

SELECT count(*) AS sclr_0 FROM blog_article b0_ WHERE b0_.test_field LIKE '%CA%';

pbaumes avatar Nov 10 '25 14:11 pbaumes

@pbaumes I tested this and it definitely works! And less complicated than creating a new entity. Appreciate your help, thanks!

I can’t say it was very intuitive that the Filter and Field don’t work the same way, but at least it works. Hopefully this ticket will be helpful for others until it gets improved (which I don’t feel comfortable doing myself, unfortunately).

mhbailly avatar Nov 18 '25 21:11 mhbailly