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

Symfony CollectionType仅保存最后新增项的技术求助

Symfony CollectionType 新增子表单仅最后一项保存问题

在自定义表单类型中使用Symfony CollectionType时,添加并填写两个新子表单提交后,仅最后一项被保存,已耗时四小时排查无果。

按官方教程使用jQuery结合CollectionType提供的prototype实现子表单添加功能,调试发现提交数据正确,但表单对象hydrate时所有新增项均被替换为最后一项。

使用环境:PHP 8.1、Symfony 5.4,已准备可复现该问题的仓库。


表单类型代码

class CustomType extends AbstractType
{
    public function buildForm(...)
    {
        $builder->add(
            'collection',
            CollectionType::class,
            [
                'required' => false,
                'entry_type' => CustomItemType::class,
                'allow_add' => true,
                'allow_delete' => true,
                'prototype' => true,
                'label' => 'Some label',
                'by_reference' => false,
                'error_bubbling' => false,
                'entry_options' => [
                    'empty_data' => new CustomItem(),
                    'by_reference' => false
                ]
            ]
        );
    }

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

子表单添加JS代码

function addItem(e) {
    e.preventDefault();

    var collectionSelector = $(this).data('collection-selector');
    var list = $(collectionSelector);

    var counter = list.data('widget-counter');

    var newWidget = list.data('prototype');
    var newHtmlElem = newWidget.replace(/__name__/g, counter);

    var newElem = $(newHtmlElem);

    newElem.on('click', e.data.removeButtonClass, {itemContainerClass: e.data.itemContainerClass}, removeItem);

    counter++;
    list.data('widget-counter', counter);

    var accordianContainer = $(collectionSelector + ' ' + e.data.collapse);
    newElem.appendTo(accordianContainer);
}

$(document).ready(function () {
    $('body').tooltip({selector: '.custom-tooltip'});

    $('.add-custom-item-btn').click({removeButtonClass: '.remove-custom-item-btn', itemContainerClass: '.custom-item-item', collapse: '#custom-item-accordion'}, addItem);

    $('.remove-custom-item-btn').click({itemContainerClass: '.custom-item-item'}, removeItem);
});

Twig模板代码片段

{% macro printItem(custom_item, index) %}
<div class="panel panel-default custom-item-item">
    <div class="panel-heading" role="tab" id="custom-item-heading-{{ index }}">
        <h4 class="panel-title">
            <a role="button"
                data-toggle="collapse"
                data-parent="#custom-item-accordion"
                href="#custom-item-collapse-{{ index }}"
                class="collapsed"
            >
                Custom Item
            </a>
        </h4>
    </div>
    <div id="custom-item-collapse-{{ index }}"
        class="panel-collapse collapse"
        role="tabpanel"
        aria-labelledby="custom-item-heading-{{ index }}"
        aria-expanded="false"
    >
        <div class="panel-body">
            {{ form_row(custom_item) }}
            <button type="button" class="remove-custom-item-btn btn btn-primary btn-sm">
                <span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
            </button>
        </div>
    </div>
</div>
{% endmacro %}

{% import _self as formMacros %}

<div class="row">
    <div class="col-xs-12 form-group">
        <button type="button" class="add-custom-item-btn btn btn-primary btn-sm" data-collection-selector="#custom-container-fields-list">
            <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
        </button>
    </div>
    <div id="custom-container-fields-list"
        data-prototype="{{ formMacros.printItem(form.collection.vars.prototype, '__name__') }}"
        data-widget-counter="{{ max(form.collection|keys) + 1 }}"
    >
        <div class="panel-group" id="custom-item-accordion" role="tablist" aria-multiselectable="true">
            {% for index, custom_item in form.collection %}
            {{ formMacros.printItem(custom_item, index) }}
            {% endfor %}
        </div>
    </div>
</div>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 16:55:28