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

Symfony 5为CollectionType过滤实体 隐藏Performer等于Service Performer的行

问题原因

你之前的实现思路存在两个核心错误:

  1. removeElement() 是 Doctrine Collection 类的方法,子表单的 FormInterface 没有该方法,无法在单个Service子表单内删除自己所在的Collection条目
  2. PRE_SET_DATA事件作用在子表单时,Collection已经完成了初始条目生成,此时无法移除整行,只会导致表单和底层数据不匹配

解决方案:在父表单层过滤Collection数据

直接在PerformerServiceType中添加PRE_SET_DATA事件,提前过滤掉不符合要求的Service条目即可,不需要修改子表单逻辑:

<?php

namespace App\Form;

use App\Entity\User;
use Doctrine\Common\Collections\Criteria;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
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\OptionsResolver\OptionsResolver;


class PerformerServiceType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('performer_services',CollectionType::class,[
                'entry_type' => ServicePerformerNoMoneyUnitType::class,
                'entry_options' => ['label' => false],
                'allow_add' => true,
                'allow_delete' => true,
                // 设为false避免修改原实体的原始数据,防止误删数据库条目
                'by_reference' => false,
            ])
            ->add('enregistrer', SubmitType::class);

        // 添加事件过滤不符合要求的条目
        $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
            /** @var User $user */
            $user = $event->getData();
            $form = $event->getForm();

            if (!$user) {
                return;
            }

            // 用Criteria过滤集合,不会修改原实体的原始数据
            $criteria = Criteria::create()
                ->where(Criteria::expr()->neq('performer', 'servicePerformer'));
            $filteredServices = $user->getPerformerServices()->matching($criteria);

            // 把过滤后的集合赋值给表单字段
            $form->get('performer_services')->setData($filteredServices);
        });
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => User::class,
        ]);
    }
}

优化建议

为了避免空对象、代理对象导致的比较异常,建议你判断两个关联字段相等时,直接比对主键ID更稳妥:

// 过滤条件可以替换为更严谨的版本
$criteria = Criteria::create()
    ->where(Criteria::expr()->neq('performer.id', 'servicePerformer.id'));

同时你可以删掉原来加在ServicePerformerNoMoneyUnitType里的PRE_SET_DATA事件代码,已经不需要了。

内容的提问来源于stack exchange,提问作者Pax

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 18:39:02