Symfony2多重嵌套表单原型。

38

我想在一个集合类型中包含另一个集合类型。它应该看起来像这样:enter image description here

只使用一个集合可以正常工作,但我需要编辑外部表单的原型,以便为每行呈现内部表单的原型。

有什么想法可以做到这一点吗?同时,保存的最佳方法是什么?

编辑: 现在我正在尝试呈现嵌套表单的原型:

  <ul class="characteristics-container" data-prototype="{{ form_widget(form.characteristics.vars.prototype)|e }}" data-prototype-options="{{ form_widget(form.characteristics.options.vars.prototype|e ) }}">
                    {# iterate over each existing tag and render its only field: name #}
                    {% for characteristic in form.characteristics %}
                        <li>{{ form_row(characteristic.name) }}</li>

                        <div class="characteristics-options">
                            {% for opt in form.characteristics.options %}

                            {% endfor %}                     
                        </div>


                    {% endfor %}
                </ul>

form_widget(form.characteristics.options.vars.prototype|e中出现了错误。

Method "options" for object "Symfony\Component\Form\FormView" does not exist in 

我尝试使用characteristics[0],但是它显示键不存在

这是我的表单类:

PromotionType(基本表单)

$builder              
            ->add('characteristics','collection', array(
                'label'         => 'Caracteristicas',
                 'type'         => new PromotionCharacteristicType(),
                 'allow_add'    => true,
                 'allow_delete' => true,
                 'by_reference' => false
            ))

促销特性类型

 $builder
            ->add('name',NULL, array('label'  => 'Nome'))
            ->add('options', 'collection', array(
                'type' => new PromotionCharacteristicOptionType(),
                'allow_add' => true,
                'allow_delete' => true,      
                'prototype' => true,
                'by_reference' => false,
            ))                       
        ;

促销特征选项类型

 $builder
            ->add('name',NULL, array('label'  => 'Nome')) 
        ;

第一级原型,表现良好。


大家好。我正在尝试开发类似的表单,以创建(新的)和编辑嵌套实体。我为实体A 1:m B 1:m C开发了一个玩具Symfony 3.1捆绑包。它似乎可以工作。如果您能检查并建议如何改进/重写它,我将不胜感激。请访问https://github.com/mario6097/SimpleBundle。谢谢。 - mario
2个回答

32

表单和原型

您需要保留来自不同集合的两个原型。Symfony建议将它们存储在包含集合的div标签的data-prototype属性中。但在您的情况下,这种方法效率很低。因此,您可以手动渲染一个空的div并在其中显示原型。

例如,您有一个角色表单。

class CharacterType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('opts', 'collection', array(
            'type' => new OptionType(),
            'allow_add' => true,
            'allow_delete' => true,
            'prototype' => true,
            'prototype_name' => '__opt_prot__'
        ));
        $builder->add('char_desc', 'text');
    }

    public function getName()
    {
        return 'char';
    }
}

然后创建一个具有字符集合的表单

$form = $this->createFormBuilder()
    ->add('chars', 'collection', array(
        'type' => new CharacterType(),
        'allow_add' => true,
        'allow_delete' => true,
        'prototype_name' => '__char_prot__'
    ))
    ->getForm();

    # example data
    $form->setData(
        array(
            'chars' => array(
                array('options' => array(), 'char_desc' => 1),
                array('options' => array(), 'char_desc' => 2),
            ),
        )
    );

并获取原型

<div
    id="prots"
    data-prototype-opt="{{ form_widget(form.chars.vars.prototype.children['opts'].vars.prototype) | e }}"
    data-prototype-char="{{ form_widget(form.chars.vars.prototype) | e }}"
>
</div>

然后像这个示例一样呈现集合,或者覆盖collection_widget块


{% for char in form.chars %}
    {{ form_row(char.char_desc) }}
    <label for="">opts</label>
    {% for opt in char.opts %}
        {{ form_row(opt.text) }}
    {% endfor %}
{% endfor %}

如何保存它

如果可以的话,请使用NoSQL数据库。或者对于关系型数据库,使用实体-属性-值(EAV)模型。但是,如果您不需要浏览选项或对其进行排序,则可以将序列化数组存储在数据库中并使用Doctrine类型array


我遇到了一个与data-prototype2相关的问题:类型为"Symfony\Component\Form\FormView"的对象(带有ArrayAccess)中不存在键“0”。 - brpaz
抱歉,安装了新版本的Symfony后出现了错误。请更新我的答案。 - Alexey B.
1
感谢。只有在你的答案中,我才找到了如何在嵌套表单中访问原型: data-prototype-opt="{{ form_widget(form.chars.vars.prototype.children['opts'].vars.prototype) | e }}" - tirenweb
一些奇怪的行为:嵌套表单原型只在表单渲染之前可用!也许是我的代码有问题,也许我会为别人节省一些时间研究 :) - po_taka
1
原型的顺序很关键:最嵌套的应该先定义,然后是它的父级(反向顺序)。否则子级原型会被赋予父级,你将会在模板中得到一个空字符串。 - Vasiliy Toporov
显示剩余3条评论

1

Alexey B.的回答中,除了能够访问集合的原型之外,我似乎通常不需要使用prototype.children['opts']。我只需按如下方式使用prototype.<collection_name>:


<div
    id="prots"
    data-prototype-opt="{{ form_widget(form.chars.vars.prototype.opts.vars.prototype) | e }}"
    data-prototype-char="{{ form_widget(form.chars.vars.prototype) | e }}"
>
</div>

这是因为Twig使用点符号表示法来访问关联数组索引、同名的对象获取方法或对象属性。允许prototype.opts访问prototype['opts']prototype->getOpts()prototype->opts - Will B.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接