Symfony4 - Как отфильтровать поле EntityType с избирателем

Мне нужно отфильтровать параметры, отображаемые в поле EntityType с избирателями.

У меня есть пользовательский объект, который имеет некоторые отношения с CustomerGroup, CustomerEntity и CustomerSite. У меня есть избиратель, например, в группе клиентов. Я могу фильтровать результаты в зависимости от роли текущего пользователя в виде списка. Я использую функцию array_filter, чтобы она работала. Пример на пользовательском объекте:

        $users = array_filter($users, function (User $user) {
            return $this->isGranted('view', $user);
        });

Я погуглил много страниц без какого-либо успеха! Я попытался создать пользовательскую функцию в CustomerGroupRepository и вызвать ее из опции query_builder в FormType: она выдает ошибку. Смотрите чуть ниже: CustomerGroupRepository.php:

    {
        $customerGroups = $this->createQueryBuilder('cg')
            ->orderBy('cg.name', 'ASC')
        ->getQuery()->getArrayResult();

        $customerGroups = array_filter($customerGroups, function (CustomerGroup $group) {
            return $this->security->isGranted('view', $group);
        });

        return $customerGroups;
    }

И функция Buildform с опцией query_builder:

public function buildForm(FormBuilderInterface $builder, array $options)
    {

        $builder
            ->add('email')
            ->add('firstName')
            ->add('lastName')
            ->add('isActive')
            ->add('CustomerGroup', EntityType::class, [
                'class' => CustomerGroup::class,
                'label' => 'name',
                'query_builder' => function(CustomerGroupRepository $er) {
                    return $er->findAllGranted();
                },
                'is_granted_disabled' => $options['is_granted_disabled'],
                'is_granted_attribute' => 'ROLE_ADMIN',
                'is_granted_subject_path' => 'parent.data',
                'choice_label' => 'name',
                'multiple' => false,
                'expanded' => false
            ]);
        $builder->addEventListener(FormEvents::PRE_SET_DATA, array($this, 'onPreSetDataEntity'));
        $builder->addEventListener(FormEvents::PRE_SUBMIT, array($this, 'onPreSubmitEntity'));
        $builder->addEventListener(FormEvents::PRE_SET_DATA, array($this, 'onPreSetDataSite'));
        $builder->addEventListener(FormEvents::PRE_SUBMIT, array($this, 'onPreSubmitSite'));

Ошибка, которую я получаю:

Argument 1 passed to App\Repository\CustomerGroupRepository::App\Repository\{closure}() must be an instance of App\Entity\CustomerGroup, array given

GroupVoter.php:


namespace App\Security\Voter;

use App\Entity\CustomerGroup;
use App\Entity\User;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Core\User\UserInterface;

class GroupVoter extends Voter
{
    private $security;

    public function __construct(Security $security)
    {
        $this->security = $security;
    }

    protected function supports($attribute, $subject)
    {
        // replace with your own logic
        // https://symfony.com/doc/current/security/voters.html
        return in_array($attribute, ['view', 'edit'])
            && $subject instanceof CustomerGroup;
    }

    protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
    {
        $user = $token->getUser();
        // if the user is anonymous, do not grant access
        if (!$user instanceof UserInterface) {
            return false;
        }

        // ... (check conditions and return true to grant permission) ...
        switch ($attribute) {
            case 'edit':
                // logic to determine if the user can EDIT
                // return true or false
                break;
            case 'view':
                return $this->canView($subject, $user);
                break;
        }

        return false;
    }

    /**
     * @param CustomerGroup $object
     * @param User $loggedUser
     * @return bool
     */
    public function canView(CustomerGroup $object, User $loggedUser)
    {
        if($this->security->isGranted('ROLE_ADMIN'))
            return true;

        elseif($this->security->isGranted('ROLE_GROUP_MANAGER'))
        {
            if($object === $loggedUser->getCustomerGroup())
                return true;
        }
        elseif($this->security->isGranted('ROLE_ENTITY_MANAGER'))
        {
            if($object === $loggedUser->getCustomerEntity()->getCustomerGroup())
                return true;
        }
        elseif($this->security->isGranted('ROLE_TECHNICIAN'))
        {
            $customerSites = $loggedUser->getCustomerSites();
            foreach ($customerSites as $site)
            {
                static $retour = false;
                if($site->getCustomerEntity()->getCustomerGroup() === $object)
                    $retour = true;
            }
            return $retour;

        }



        return false;
    }
}

UserFormType.php:


namespace App\Form;

use App\Entity\CustomerEntity;
use App\Entity\CustomerGroup;
use App\Entity\CustomerSite;
use App\Entity\User;
use App\Repository\CustomerGroupRepository;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;


class UserFormType extends AbstractType
{
    private $tokenStorage;
    private $em;

    public function __construct(TokenStorageInterface $tokenStorage, EntityManagerInterface $em)
    {
        $this->tokenStorage = $tokenStorage;
        $this->em = $em;
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {

        $builder
            ->add('email')
            ->add('firstName')
            ->add('lastName')
            ->add('isActive')
            ->add('CustomerGroup', EntityType::class, [
                'class' => CustomerGroup::class,
                'label' => 'name',
                'is_granted_disabled' => $options['is_granted_disabled'],
                'is_granted_attribute' => 'ROLE_ADMIN',
                'is_granted_subject_path' => 'parent.data',
                'choice_label' => 'name',
                'multiple' => false,
                'expanded' => false
            ]);
        $builder->addEventListener(FormEvents::PRE_SET_DATA, array($this, 'onPreSetDataEntity'));
        $builder->addEventListener(FormEvents::PRE_SUBMIT, array($this, 'onPreSubmitEntity'));
        $builder->addEventListener(FormEvents::PRE_SET_DATA, array($this, 'onPreSetDataSite'));
        $builder->addEventListener(FormEvents::PRE_SUBMIT, array($this, 'onPreSubmitSite'));

    }

    ...

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => User::class,
            'is_granted_attribute' => null,
            'is_granted_subject_path' => null,
            'is_granted_hide' => false,
            'is_granted_disabled' => false
        ]);
    }
}

Параметры, доступные в поле CustomerGroup в форме, не фильтруются Symfony. Я могу видеть все группы клиентов, даже если моя роль не позволяет им.

РЕДАКТИРОВАТЬ: Может быть, я должен использовать атрибут "choises". Мне нужно получить доступ к CustomerGroupRepository, чтобы сделать это!

Спасибо за вашу помощь!

Лучший,

Julien

1 ответ

Решение

Спасибо за ваши советы!

Наконец, мне удалось заставить его работать, создав пользовательскую функцию "FindByGranted" в репозитории. Например:

public function findAllGranted()
    {
        $customerGroups = $this->createQueryBuilder('cg')
            ->orderBy('cg.name', 'ASC')
        ->getQuery()->execute();

        $customerGroups = array_filter($customerGroups, function (CustomerGroup $group) {
            return $this->security->isGranted('view', $group);
        });
        return $customerGroups;
    }

Затем я вызываю эту функцию из formType.

Спасибо вам всем.

С Уважением,

Другие вопросы по тегам