Symfony 5.1 - 提交前动态添加 CustomType 字段

Symfony 5.1 - Dynamically add a CustomType field before submitting

我的问题没那么简单我会尽量总结一下。

假设我有一个实体 Vehicle,它与实体 Engine 相关。 Engine 实体是由 2 类 实现的抽象类型:ElectricEngineGasEngine .

我想为 Vehicle 创建一个表单,它将创建一个车辆及其引擎类型,但我无法添加绑定了 Engine 实体的 CustomType 字段,因为它是一个抽象实体.所以我需要使用 ElectricEngineGasEngine 动态添加 CustomType 字段。这是 VehicleType.php :

// App\Form\VechicleType::buildForm
$builder
        ->add('wheels', IntegerType::class)
        ->add('type', ChoiceType::class, [
            'choices' => [
                'ElectricEngine' => 1,
                'GasEngine' => 2
            ],
            'mapped' => false
        ])

所以当用户提交此表单时,我想取消提交并添加我的 ElectricEngineType 或我的 GasEngineType 字段,具体取决于哪一个我的用户选择了。

目前,这是我的解决方案:我在构建 VehicleForm 时使用 POST_SUBMIT 事件。我正在观察用户选择的类型,并添加匹配的字段。然后我添加一个错误以取消提交,以便再次呈现表单,但使用新字段。

// App\Form\VehicleTypeForm::buildForm
// After building form ...
$builder->get('type')->addEventListener(FormEvents::POST_SUBMIT, function(FormEvent $event){
        $form = $event->getForm()->getParent();

        if($form->get('type')->getData() != null) {
            switch ($form->get('type')->getData()) {
                case 1:
                    $form->add('engine', ElectrineEngine::class);
                    $form->remove('type');
                    break;
                case 2:
                    $form->add('engine', GasEngine::class);
                    $form->remove('type');
                    break;
                default:
                    // Do Nothing
            }
            // Adding Error so the form is not submitted
            $form->addError(new FormError('Adding engine field'));
        }
    });

通过添加错误,表单不再有效,因此将再次呈现。 如果有人和我有同样的问题,这是一个解决方案。

但我认为它不是最好的,因为我在表格中添加了一个错误,并且没有错误。我想有一个更好的方法来实现这个,但我不知道该怎么做。

我考虑过使用 https://github.com/craue/CraueFormFlowBundle 来使用多个步骤,但这会添加电动引擎和燃气引擎步骤,我们将不得不跳过一个。我认为这不是最好的主意,因为在我的真实项目中(当然我没有开发任何车辆和引擎)我有抽象实体的 3 个子代,而且还会有更多。也许这个捆绑包是最好的主意,但我不太确定:/

我找到了更好的解决方案。对于遇到同样问题的人,这是给你的。

最好的方法是拥有多种形式,每次都添加通用部分,而不是做一种通用形式并对其进行调整。是我笨,没想到

以车辆为例:我们将有一个带有通用字段的 VehicleForm。这里是 ElectricEngineForm :

// App\Form\ElectricEngineForm
public function buildForm(FormBuilderInterface $builder, array $options)
{
    $genericType = new VehicleType();
    $genericType->buildForm($builder, $options);
    $builder->add('engine', ElectricEngineType::class);
}


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

ElectricEngineType 是包含 ElectricEngine 特性的形式。您还必须创建 GasEngineForm 和 GasEngineType。然后根据用户选择的路线渲染你想要的那个。

如果用户在 /vehicle/add/electric,那么我们渲染 ElectricEngineForm,否则如果他在 /vehicle/add/gas,那么我们渲染 GasEngineForm。

如果您愿意,可以使用我认为的其他方法构建通用表单。也许是静态方法,否则我不知道。