php Symfony CollectionType仅保存上次提交的新项目

pu82cl6c  于 2022-10-30  发布在  PHP
关注(0)|答案(1)|浏览(105)

因此,我的自定义表单类型中的CollectionType出现问题。当我向集合中添加两个新表单并正确填写它们并提交时,只有最后一个选项被提交。过去四个小时我一直在绞尽脑汁试图解决这个问题。

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]);
    }
}

如果您需要更多信息,请询问我,我将提供。我已经使用jQuery和CollectionType类提供的原型实现了子表单的添加。我在www.example.com上学习了教程symfony.com,现在我不知道该往哪个方向走。任何帮助都是非常感谢的。
我确实对表单做了一些调试,数据被正确提交,但是当它对表单对象进行水合时,它会为添加的每个条目传递表单中的最后一项。

编辑

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);
});

这是tweg模板的一个片段

{% 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>

***编辑***我已经创建了一个repo,它演示了所有类的这个问题,这样您就可以随时查看它。不,这不是实际的代码,但问题仍然存在。我使用的是PHP 8.1和symfony 5.4,但所有这些都可以在下面的repo中的composer.json文件中看到。如果有人能提供一些信息,我将非常感激。或者,如果大家一致认为这是一个bug,我会用symfony记录一个bug,但我宁愿先确定这一点。

Repo that reproduces the issue

k4ymrczo

k4ymrczo1#

您的问题似乎是由CustomType中的这一行引起的:

'empty_data' => new CustomItem(),

由于您已经将empty_data设置为CustomItem的单个示例,因此每个新行都将重用此相同的示例。
CollectionType上,您还将by_reference设置为false,这意味着CustomContainer类上的adder方法将使用相同的CustomItem示例为每个新行调用。假设您已经使用了make:entity命令,则该adder方法仅在CustomItem对象的数组中不存在相同的示例时才添加该对象,这就解释了缺少项的原因。
解决方案是为每个新行创建一个新的CustomItem示例,如下面的示例所示:https://webmozart.io/blog/2015/09/09/value-objects-in-symfony-forms/(在The empty_data Option下)

'empty_data' => function (FormInterface $form) {
    return new CustomItem();
},

相关问题