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

Symfony实现动态添加表单输入并存储JSON类型exception字段求助

解决Symfony中动态添加JSON类型异常字段的问题

我来帮你搞定这个动态添加异常项并存为JSON的问题,按照下面的步骤一步步来就行:

1. 创建异常项的子表单类型

首先,我们需要为单个异常项创建一个子表单,因为每个异常包含名称、日期、时间这些字段。新建App\Form\ExceptionItemType:

<?php
namespace App\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\TimeType;

class ExceptionItemType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name', TextType::class, [
                'label' => '异常名称'
            ])
            ->add('startDate', DateType::class, [
                'label' => '开始日期',
                'widget' => 'single_text' // 用单文本框选择日期,更友好
            ])
            ->add('endDate', DateType::class, [
                'label' => '结束日期',
                'widget' => 'single_text'
            ])
            ->add('startTime', TimeType::class, [
                'label' => '开始时间',
                'widget' => 'single_text'
            ])
            ->add('endTime', TimeType::class, [
                'label' => '结束时间',
                'widget' => 'single_text'
            ]);
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'template' => 'form/exception_item_type.html.twig' // 后面会自定义这个模板
        ]);
    }
}

2. 更新主表单类TypeParkingType

把原来的exception字段改成CollectionType,这样Symfony就能处理一组异常项:

<?php
namespace App\Form;

use App\Entity\TypeParking;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\TimeType;
use Symfony\Component\Form\Extension\Core\Type\DateType;

class TypeParkingType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('libelle', TextType::class)
            ->add('tempsmax', TimeType::class, [
                'widget' => 'single_text'
            ])
            ->add('jourdebut', DateType::class, [
                'widget' => 'single_text'
            ])
            ->add('jourfin', DateType::class, [
                'widget' => 'single_text'
            ])
            ->add('heurstravail') // 如果这个字段也是类似结构,也可以用同样的CollectionType处理
            ->add('exception', CollectionType::class, [
                'entry_type' => ExceptionItemType::class,
                'allow_add' => true, // 允许添加新项
                'allow_delete' => true, // 允许删除项
                'by_reference' => false, // 必须设为false,因为我们要修改数组
                'label' => '异常设置',
                'prototype' => true, // 启用表单原型,用于动态复制
                'prototype_name' => '__exception_index__', // 占位符,后面JS会替换
                'attr' => [
                    'class' => 'exception-collection' // 给容器加个类,方便JS定位
                ]
            ]);
    }

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

3. 自定义异常项的Twig模板

创建templates/form/exception_item_type.html.twig,美化每个异常项的布局,还加个删除按钮:

<div class="form-row mb-3">
    <div class="col-md-2">
        {{ form_label(form.name) }}
        {{ form_widget(form.name) }}
        {{ form_errors(form.name) }}
    </div>
    <div class="col-md-2">
        {{ form_label(form.startDate) }}
        {{ form_widget(form.startDate) }}
        {{ form_errors(form.startDate) }}
    </div>
    <div class="col-md-2">
        {{ form_label(form.endDate) }}
        {{ form_widget(form.endDate) }}
        {{ form_errors(form.endDate) }}
    </div>
    <div class="col-md-2">
        {{ form_label(form.startTime) }}
        {{ form_widget(form.startTime) }}
        {{ form_errors(form.startTime) }}
    </div>
    <div class="col-md-2">
        {{ form_label(form.endTime) }}
        {{ form_widget(form.endTime) }}
        {{ form_errors(form.endTime) }}
    </div>
    <div class="col-md-2 d-flex align-items-end">
        <button type="button" class="btn btn-danger btn-remove-exception">删除</button>
    </div>
</div>

4. 更新实体类的exception字段

推荐把json_array改成json(Symfony 3.4+支持,更贴合数据库JSON字段),还要确保有正确的getter和setter:

class TypeParking {
    // ... 其他字段

    /**
     * @ORM\Column(type="json", nullable=true)
     */
    private $exception = []; // 初始化为空数组,避免null问题

    // ... 其他getter/setter

    public function getException(): ?array
    {
        return $this->exception;
    }

    public function setException(?array $exception): self
    {
        $this->exception = $exception;

        return $this;
    }
}

5. 修改Twig表单模板(new.html.twig)

添加动态添加按钮和JS代码,实现点击“+”新增异常项:

{% extends 'base.html.twig' %}

{% block body %}
    <h1>创建新停车类型</h1>

    {{ form_start(form) }}
        {{ form_widget(form) }}

        <!-- 添加异常项的按钮 -->
        <button type="button" id="add-exception" class="btn btn-success mt-3">+ 添加异常</button>

        <div class="mt-3">
            <button type="submit" class="btn btn-primary">保存</button>
        </div>
    {{ form_end(form) }}

    <!-- 隐藏的表单原型,用于动态复制 -->
    {% set exception_prototype = form.exception.vars.prototype %}
    <div id="exception-prototype" class="d-none">
        {{ form_widget(exception_prototype) }}
    </div>

    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script>
        $(document).ready(function() {
            const $collectionHolder = $('.exception-collection');
            const $prototype = $('#exception-prototype').html();
            // 初始索引值为现有异常项的数量
            let index = $collectionHolder.find('.form-row').length;

            // 点击按钮添加新异常项
            $('#add-exception').click(function() {
                // 替换原型中的占位符,确保每个表单字段的name属性唯一
                const newForm = $prototype.replace(/__exception_index__/g, index);
                $collectionHolder.append(newForm);
                index++;
            });

            // 点击删除按钮移除对应的异常项
            $collectionHolder.on('click', '.btn-remove-exception', function() {
                $(this).closest('.form-row').remove();
            });
        });
    </script>
{% endblock %}

最后测试一下

现在你启动Symfony服务器,访问/new页面,就能看到“添加异常”按钮了,点击它会动态生成一组输入项,填写后提交表单,数据库里的exception字段就会存储成你想要的JSON格式啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:55:53