EasyAdminBundle icon indicating copy to clipboard operation
EasyAdminBundle copied to clipboard

[ChoiceFilter][Bug]

Open GrinWay opened this issue 9 months ago • 0 comments

Description Dealing with ChoiceFilter something going wrong, because I actually can't filter by User::roles using this choice filter

Reproduce Just create a custom choice filter called as RolesFilter:

<?php

namespace App\Admin\Filter;

use App\Form\Admin\Field\RolesFilterFormType;
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;

class RolesFilter implements FilterInterface
{
    use FilterTrait;

    public static function new(string $propertyName = 'roles', $label = null): self
    {
        return (new self())
            ->setFilterFqcn(__CLASS__)
            ->setProperty($propertyName)
            ->setLabel($label)
            ->setFormType(RolesFilterFormType::class)//
            ;
    }

    public function apply(QueryBuilder $queryBuilder, FilterDataDto $filterDataDto, ?FieldDto $fieldDto, EntityDto $entityDto): void
    {
        $role = $filterDataDto->getValue();

        $alias = $filterDataDto->getEntityAlias();
        $prop = $filterDataDto->getProperty();
        $whereStatement = \sprintf('%s.%s = :role', $alias, $prop);

        $queryBuilder
            ->andWhere($whereStatement)
            ->setParameter('role', $role)//
        ;
    }
}

and RolesFilterFormType:

<?php

namespace App\Form\Admin\Field;

use App\Type\Security\SecurityRoleType;
use EasyCorp\Bundle\EasyAdminBundle\Form\Filter\Type\ChoiceFilterType;
use EasyCorp\Bundle\EasyAdminBundle\Form\Type\ComparisonType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class RolesFilterFormType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('comparison', HiddenType::class, [
                'data' => ComparisonType::CONTAINS,
            ])//
        ;
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'value_type' => ChoiceType::class,
            'value_type_options' => [
                'choices' => SecurityRoleType::ALL,
                'multiple' => false,
                'row_attr' => [
                    'style' => 'margin-top: -0.3rem;',
                ],
            ],
        ]);
    }

    public function getParent(): string
    {
        return ChoiceFilterType::class;
    }
}

Security role types:

<?php

namespace App\Type\Security;

/**
 * ALL SECURITY TYPES
 */
class SecurityRoleType
{
    public const ROLE_USER = 'ROLE_USER';
    public const ROLE_EMPLOYEE = 'ROLE_EMPLOYEE';
    public const ROLE_MANAGER = 'ROLE_MANAGER';
    public const ROLE_ADMIN = 'ROLE_ADMIN';

    public const ROLE_DRIVER_EMPLOYEE = 'ROLE_DRIVER_EMPLOYEE';
    public const ROLE_SUPER_EMPLOYEE = 'ROLE_SUPER_EMPLOYEE';

    public const ROLE_ORDER_MANAGER = 'ROLE_ORDER_MANAGER';
    public const ROLE_SUPER_MANAGER = 'ROLE_SUPER_MANAGER';

    public const ROLE_CONFIG_ADMIN = 'ROLE_CONFIG_ADMIN';
    public const ROLE_PRICING_ADMIN = 'ROLE_PRICING_ADMIN';
    public const ROLE_TELEGRAM_BOT_ADMIN = 'ROLE_TELEGRAM_BOT_ADMIN';
    public const ROLE_SUPER_ADMIN = 'ROLE_SUPER_ADMIN';

    public const ALL = [
        'ROLE_USER' => self::ROLE_USER,
        'ROLE_EMPLOYEE' => self::ROLE_EMPLOYEE,
        'ROLE_MANAGER' => self::ROLE_MANAGER,
        'ROLE_ADMIN' => self::ROLE_ADMIN,

        'ROLE_DRIVER_EMPLOYEE' => self::ROLE_DRIVER_EMPLOYEE,
        'ROLE_SUPER_EMPLOYEE' => self::ROLE_SUPER_EMPLOYEE,

        'ROLE_ORDER_MANAGER' => self::ROLE_ORDER_MANAGER,
        'ROLE_SUPER_MANAGER' => self::ROLE_SUPER_MANAGER,

        'ROLE_CONFIG_ADMIN' => self::ROLE_CONFIG_ADMIN,
        'ROLE_PRICING_ADMIN' => self::ROLE_PRICING_ADMIN,
        'ROLE_TELEGRAM_BOT_ADMIN' => self::ROLE_TELEGRAM_BOT_ADMIN,
        'ROLE_SUPER_ADMIN' => self::ROLE_SUPER_ADMIN,
    ];
}

Above example is not filtering my User::roles

IN (:role) also not working

but if I compare using LIKE statement it's working, but I can't compare several roles at the same time with this approach :(

WORKS:

<?php

namespace App\Admin\Filter;

use App\Form\Admin\Field\RolesFilterFormType;
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;

class RolesFilter implements FilterInterface
{
    use FilterTrait;

    public static function new(string $propertyName = 'roles', $label = null): self
    {
        return (new self())
            ->setFilterFqcn(__CLASS__)
            ->setProperty($propertyName)
            ->setLabel($label)
            ->setFormType(RolesFilterFormType::class)//
            ;
    }

    public function apply(QueryBuilder $queryBuilder, FilterDataDto $filterDataDto, ?FieldDto $fieldDto, EntityDto $entityDto): void
    {
        $role = $filterDataDto->getValue();

        $alias = $filterDataDto->getEntityAlias();
        $prop = $filterDataDto->getProperty();
        $whereStatement = \sprintf('%s.%s LIKE :role', $alias, $prop);

        $queryBuilder
            ->andWhere($whereStatement)
            ->setParameter('role', \sprintf('%%%s%%', $role))//
        ;
    }
}

HIGHLY STRANGE...

(OPTIONAL) Additionally I have to say that I translated all the roles, but it shouldn't influence

GrinWay avatar Apr 12 '25 15:04 GrinWay