Symfony表单收件人权限过滤问题求助
解决Symfony表单EntityType过滤收件人时的Doctrine类型错误
问题原因
class参数类型错误:Doctrine的EntityType要求class必须是实体类的完整类名字符串,你传入了闭包,导致类型不匹配触发报错。- 错误的过滤逻辑位置:你试图在
class选项中返回查询构建器,这是误用配置项,正确的过滤选项是query_builder。 - 不规范的用户获取方式:直接操作
$_SESSION不符合Symfony最佳实践,应该使用Security组件获取当前用户。
解决方案
- 保持
class为Users::class,通过query_builder选项根据用户角色过滤收件人。 - 注入
Security组件获取当前用户,避免直接操作Session。 - 根据用户角色构建对应的查询条件:普通用户只显示管理员,管理员显示所有用户。
修改后的代码
1. 表单类型(MessageType.php)
use App\Entity\Messages; use App\Entity\Users; use App\Repository\UsersRepository; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Extension\Core\Type\TextareaType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Security\Core\Security; class MessageType extends AbstractType { private $security; // 注入Security服务获取当前用户 public function __construct(Security $security) { $this->security = $security; } public function buildForm(FormBuilderInterface $builder, array $options): void { $currentUser = $this->security->getUser(); $builder ->add('title', TextType::class, [ "attr" => ["class" => "form-control"] ]) ->add('message', TextareaType::class, [ "attr" => ["class" => "form-control"] ]) ->add('recipient', EntityType::class, [ "class" => Users::class, // 固定为实体类字符串 "choice_label" => "firstname", "attr" => ["class" =>"form-control"], "query_builder" => function (UsersRepository $ur) use ($currentUser) { $qb = $ur->createQueryBuilder('u'); // 普通用户仅显示管理员 if (!$currentUser->hasRole('ROLE_ADMIN')) { // 根据你的roles字段存储方式调整条件: // 如果roles是字符串(如"ROLE_ADMIN"): $qb->where('u.roles = :role') ->setParameter('role', 'ROLE_ADMIN'); // 如果roles是JSON数组(Symfony默认存储格式): // $qb->where('JSON_CONTAINS(u.roles, :role)') // ->setParameter('role', '"ROLE_ADMIN"'); } return $qb; }, ]) ->add('Envoyer', SubmitType::class, [ "attr" => ["class" => "btn btn-primary"] ]) ; } public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'data_class' => Messages::class, ]); } }
2. 控制器部分(仅需确保用户获取规范)
#[Route("/send", name: '_send')] public function send(Request $request, EntityManagerInterface $em): Response { $message = new Messages(); $form = $this->createForm(MessageType::class, $message); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()){ $message ->setTitle($form->get('title')->getData()) ->setMessage($form->get('message')->getData()) ->setRecipient($form->get('recipient')->getData()) ->setSender($this->getUser()) // 使用Symfony内置方法获取当前用户 ; $em->persist($message); $em->flush(); $this->addFlash("message", "Votre mesage a été envoyé."); return $this->redirectToRoute("messages_view"); } return $this->render("messages/send.html.twig", [ "form" => $form->createView() ]); }
关键注意点
- 确保
Users实体的roles字段存储方式和查询条件匹配:字符串类型直接比较,JSON数组类型使用JSON_CONTAINS。 $currentUser->hasRole('ROLE_ADMIN')是Symfony判断用户角色的标准方法,会自动处理角色继承逻辑。- 禁止直接操作
$_SESSION,依赖Security组件能保证用户认证状态的正确性和安全性。
内容的提问来源于stack exchange,提问作者Armad
相关产品推荐
相关产品推荐

