EasyAdminBundle
EasyAdminBundle copied to clipboard
An entityFilter (not equal) doesn't work correctly when user can choose more than one option
EntityFilter works well when you can select only one option but in my case, I allow the user to choose severals option :

Now if I filter by not equal James Harveyd this is my result :

I don't understand why EA make appear the second line, any idea ?
How do you make EntityFilter suitable for multiple selections? As far as I can see only one can be selected
@parijke You can choose multiple options if you are in ManyToMany
It's hard to make sql query. I made another filter, that works fine for me.
Usage:
$filters->add(EntityAssocFilter::new('properties', 'value')
->setLabel('Properties')
->setChoices($this->propertyValueRepository->findAllChoices())
->canSelectMultiple(true)
->setFormTypeOption('value_type_options.attr.data-widget', null)
->setFormTypeOption('value_type_options.attr.size', 10)
);
Code:
use Doctrine\ORM\Query\Expr\Orx;
use Doctrine\ORM\QueryBuilder;
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Filter\FilterInterface;
use EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto;
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto;
use EasyCorp\Bundle\EasyAdminBundle\Dto\FilterDataDto;
use EasyCorp\Bundle\EasyAdminBundle\Filter\FilterTrait;
use EasyCorp\Bundle\EasyAdminBundle\Form\Filter\Type\ChoiceFilterType;
use EasyCorp\Bundle\EasyAdminBundle\Form\Type\ComparisonType;
final class EntityAssocFilter implements FilterInterface
{
use FilterTrait;
private string $assocPropertyName;
public static function new(string $propertyName, string $assocPropertyName, $label = null): self
{
return (new self())
->setFilterFqcn(__CLASS__)
->setProperty($propertyName)
->setAssocPropertyName($assocPropertyName)
->setLabel($label)
->setFormType(ChoiceFilterType::class)
;
}
public function getAssocPropertyName(): string
{
return $this->assocPropertyName;
}
public function setAssocPropertyName(string $assocPropertyName): self
{
$this->assocPropertyName = $assocPropertyName;
return $this;
}
public function setChoices(array $choices): self
{
$this->dto->setFormTypeOption('value_type_options.choices', $choices);
return $this;
}
public function renderExpanded(bool $isExpanded = true): self
{
$this->dto->setFormTypeOption('value_type_options.expanded', $isExpanded);
return $this;
}
public function canSelectMultiple(bool $selectMultiple = true): self
{
$this->dto->setFormTypeOption('value_type_options.multiple', $selectMultiple);
return $this;
}
public function apply(QueryBuilder $queryBuilder, FilterDataDto $filterDataDto, ?FieldDto $fieldDto, EntityDto $entityDto): void
{
$alias = $filterDataDto->getEntityAlias();
$property = $filterDataDto->getProperty();
$comparison = $filterDataDto->getComparison();
$parameterName = $filterDataDto->getParameterName();
$value = $filterDataDto->getValue();
if (!is_array($value)) {
$value = [$value];
}
$isMultiple = $filterDataDto->getFormTypeOption('value_type_options.multiple');
$assocAlias = $filterDataDto->getParameterName();
$assocProperty = $this->assocPropertyName;
if ($entityDto->isToManyAssociation($property)) {
if (0 === \count($value)) {
$queryBuilder->leftJoin(sprintf('%s.%s', $alias, $property), $assocAlias);
$queryBuilder->andWhere(sprintf('%s.%s %s', $assocAlias, $assocProperty, $comparison));
} else {
$queryBuilder->leftJoin(sprintf('%s.%s', $alias, $property), $assocAlias,
'WITH', "$assocAlias.$assocProperty IN (:$parameterName)")
->setParameter($parameterName, $value);
if ('IN' === $comparison) {
$queryBuilder->andWhere(sprintf('%s.%s IS NOT NULL', $assocAlias, $assocProperty));
}
if ('NOT IN' === $comparison) {
$queryBuilder->andWhere(sprintf('%s.%s IS NULL', $assocAlias, $assocProperty));
}
}
} else if (null === $value || ($isMultiple && 0 === \count($value))) {
$queryBuilder->andWhere(sprintf('%s.%s %s', $assocAlias, $assocProperty, $comparison));
} else {
$orX = new Orx();
$orX->add(sprintf('%s.%s %s (:%s)', $assocAlias, $assocProperty, $comparison, $parameterName));
if (ComparisonType::NEQ === $comparison) {
$orX->add(sprintf('%s.%s IS NULL', $assocAlias, $assocProperty));
}
$queryBuilder->andWhere($orX)
->setParameter($parameterName, $value);
}
}
}