You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 11:18:02