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.
Спасибо вам всем.
С Уважением,