Symfony5 无Doctrine关联实体按公共字段筛选EntityType可选值
实现方案
这个需求属于Symfony动态联动下拉场景,我们可以通过Symfony表单事件系统+前端监听提交实现,无需修改实体关联配置,具体实现步骤如下:
1. 修改表单类型ReclamationType
首先引入表单事件相关类,通过事件监听在Gerance字段值确定后,动态过滤NatRec的可选值:
<?php namespace App\Form; use App\Entity\Gerance; use App\Entity\NatRec; use App\Entity\Reclamation; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; 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; class ReclamationType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('nom') ->add('adressere') ->add('numetelep') ->add('numerofax') ->add('adresmail') ->add('objreclam') ->add('numegera', EntityType::class, [ 'class' => Gerance::class, 'choice_label' => 'LIBEGERA', 'placeholder' => '请选择Gerance', 'mapped' => true ]) ->add('prenom') ->add('cin') ->add('datesais') ->add('codeclie') ->add('usersais') ->add('codesect') ; // 定义动态生成NatRec下拉的通用方法 $addCodnatreField = function (FormInterface $form, ?string $numegera = null) { $form->add('codnatre', EntityType::class,[ 'class' => NatRec::class, 'choice_label' => 'LIBNATRE', 'placeholder' => $numegera ? '请选择NatRec' : '请先选择Gerance', 'query_builder' => function (\App\Repository\NatRecRepository $repo) use ($numegera) { $qb = $repo->createQueryBuilder('n'); if ($numegera) { $qb->where('n.NUMEGERA = :numegera') ->setParameter('numegera', $numegera); } else { // 未选Gerance时不返回任何选项 $qb->where('1 = 0'); } return $qb; } ]); }; // 表单初始化/编辑场景:根据已有值加载对应NatRec选项 $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($addCodnatreField) { $data = $event->getData(); $numegera = $data?->getNumegera()?->getNUMEGERA(); $addCodnatreField($event->getForm(), $numegera); }); // Gerance字段提交后:动态更新NatRec选项 $builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) use ($addCodnatreField) { $data = $event->getData(); $geranceId = $data['numegera'] ?? null; $numegera = null; if ($geranceId) { // 根据提交的GeranceID查询对应的NUMEGERA值 $em = $event->getForm()->getConfig()->getOption('em'); $gerance = $em->getRepository(Gerance::class)->find($geranceId); $numegera = $gerance?->getNUMEGERA(); } $addCodnatreField($event->getForm(), $numegera); }); } public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'data_class' => Reclamation::class, ]); } }
2. 前端实现联动逻辑
在表单渲染页面加入以下JS代码,监听Gerance下拉变化,提交表单片段更新NatRec下拉:
// 监听numegera下拉变化 document.querySelector('#reclamation_numegera').addEventListener('change', function () { const form = this.closest('form'); const formData = new FormData(); formData.append(this.name, this.value); fetch(form.action, { method: form.method, body: formData, headers: { 'X-Requested-With': 'XMLHttpRequest' } }).then(response => response.text()) .then(html => { const tempDiv = document.createElement('div'); tempDiv.innerHTML = html; const newCodnatre = tempDiv.querySelector('#reclamation_codnatre'); if (newCodnatre) { document.querySelector('#reclamation_codnatre').replaceWith(newCodnatre); } }); });
注意:如果你的表单前缀不是默认的
reclamation,请对应修改JS代码中的字段选择器。
3. 控制器适配
在处理表单的控制器中,加入AJAX请求的判断逻辑,当检测到是AJAX提交时,仅渲染表单片段返回:
// 你的表单处理控制器方法 #[Route('/reclamation/new', name: 'app_reclamation_new')] public function new(Request $request): Response { $reclamation = new Reclamation(); $form = $this->createForm(ReclamationType::class, $reclamation); $form->handleRequest($request); if ($form->isSubmitted() && $request->isXmlHttpRequest()) { // AJAX请求时仅返回表单渲染结果 return $this->render('reclamation/_form_part.html.twig', [ 'form' => $form->createView(), ]); } if ($form->isSubmitted() && $form->isValid()) { // 正常提交逻辑 $entityManager = $this->getDoctrine()->getManager(); $entityManager->persist($reclamation); $entityManager->flush(); return $this->redirectToRoute('app_reclamation_index'); } return $this->render('reclamation/new.html.twig', [ 'reclamation' => $reclamation, 'form' => $form->createView(), ]); }
你需要自行创建_form_part.html.twig模板,仅渲染表单的widget即可,不需要包含页面其他布局。如果使用Symfony UX的Autocomplete组件,也可以直接在组件配置中添加动态参数,实现起来更简洁。
内容的提问来源于stack exchange,提问作者Haru
相关产品推荐
相关产品推荐

