【问题标题】:Form with a collection same entity type具有集合相同实体类型的表单
【发布时间】:2014-05-06 07:49:56
【问题描述】:

我想要我的实体 « X » 的表单。该实体拥有与许多类型为 « X » 的实体的 OneToMany 关系。这是一个关系父 孩子。

当我简单地创建我的表单时,它可以工作。

class XType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add("name",     "text",       array("label" => "Nom"))
            ->add("children", "collection", array(
                "type"         => new XType(),
                "by_reference" => false));
    }
}

然后,我想通过选项 «allow_add » 在我的集合中轻松添加新实体,并使用原型在 javascript 中添加。这是我的带有 «allow_add » 选项的表单。

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add("name",     "text",       array("label" => "Nom"))
        ->add("children", "collection", array(
            "type"         => new XType(),
            "allow_add"    => true,
            "by_reference" => false));
}

当我在调用或不调用原型的情况下执行时,我遇到了网络服务器错误。由于递归调用太大,是 XDebug 踢了我的请求。有级联调用。

解决我的问题的最佳解决方案是什么?

【问题讨论】:

    标签: symfony


    【解决方案1】:

    我不能真正说出您的问题出在哪里,但应该在 javascript 和集合原型周围的某个地方。此外,当您允许添加项目时,您通常也允许 allow_delete。

    看看我的例子:

    $builder->add('book',   'collection',   array(
                                                    'type' => new BookType(),
                                                     'allow_add' => true,
                                                     'allow_delete' => true,
                                                     'prototype_name' => '__prototype__',
                                                     'by_reference' => false,
                                                     'error_bubbling' => false
                                                   );
    

    在您呈现表单的模板中,包含以下内容:

    {% block javascript %}
        {{ parent() }}
        {% javascripts
        '@ProjectSomeBundle/Resources/public/js/form/collection.js'
        %}
        <script type="text/javascript" src="{{ asset_url }}"></script>
        {% endjavascripts %}
    {% endblock %}
    

    collection.js 文件包含以下内容:

    $(function($) {
        $addButton = $('button.add');
        $collection = $addButton.parent().children().first();
    
        $addButton.click(function () {
            var prototype = $($collection.data('prototype').replace(/__prototype__/g, function() { return (new Date()).getTime(); }));
            prototype.appendTo($collection.children('ul'));
            });
    
        $('body').on('click', 'button.remove', function () {
            $(this).parent().remove();
        });
    });
    

    此外,您应该使用传递给 twig 的那些自定义集合小部件。没什么花哨的,它将呈现为带有项目的无序列表,以使项目易于访问。

    config.yml:

    twig:
        form:
            resources:
                - 'ProjectSomeBundle:Form:fields.html.twig'
    

    fields.html.twig:

    {% extends 'form_div_layout.html.twig' %}
    
    {% block collection_widget %}
        {% import  "ProjectSomeBundle:Macro:macro.html.twig" as macro %}
        {% spaceless %}
            <div class="collection">
                {% if prototype is defined %}
                    {% set attr = attr|merge({'data-prototype': block('prototype_widget') }) %}
                {% endif %}
                <div {{ block('widget_container_attributes') }}>
                    <ul>
                        {% for row in form %}
                            {{ macro.collection_item_widget(row) }}
                        {% endfor %}
                    </ul>
                    {{ form_rest(form) }}
                </div>
                <div class="clear"></div>
                <button type="button" class="add">{% trans %}Add{% endtrans %}</button>
            </div>
            <div class="clear"></div>
        {% endspaceless %}
    {% endblock collection_widget %}
    
    {% block prototype_widget %}
        {% spaceless %}
            {{ macro.collection_item_widget(prototype) }}
        {% endspaceless %}
    {% endblock prototype_widget %}
    

    你可以注意到它使用宏,所以这里是:

    macro.html.twig

    {% macro collection_item_widget(fields) %}
        <li>
            {% set fieldNum = 1 %}
            {% for field in fields %}
                <div class="field_{{ fieldNum }}">
                    {{ form_label(field) }}
                    {{ form_errors(field) }}
                    {{ form_widget(field) }}
                </div>
                {% set fieldNum = fieldNum + 1 %}
            {% endfor %}
            <button type="button" class="remove">{% trans %}Delete{% endtrans %}</button>
            <div class="clear"></div>
        </li>
    {% endmacro %}
    

    这是一个完整的例子,我希望你觉得它有用并且对你有用。

    【讨论】:

      【解决方案2】:

      我遇到了同样的问题(由于递归调用过多,我的 Web 服务器也崩溃了)。我的快速解决方法是简单地创建一个不包含递归字段的虚拟(克隆)类型(这对我有用,因为我只对 1 级孩子感兴趣)。

      因此,如果这种情况也适用于您,您可以按如下方式更改您的代码:

      class XType extends AbstractType
      {
          public function buildForm(FormBuilderInterface $builder, array $options)
          {
              $builder
                  ->add("name",     "text",       array("label" => "Nom"))
                  ->add("children", "collection", array(
                      "type"         => new XTypeWithoutChildren(),
                      "by_reference" => false));
          }
      }
      
      class XTypeWithoutChildren extends XType
      {
          public function buildForm(FormBuilderInterface $builder, array $options)
          {
              $builder
                  ->add("name",     "text",       array("label" => "Nom"));
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2018-02-22
        • 2013-03-03
        • 2014-03-12
        • 1970-01-01
        • 1970-01-01
        • 2014-10-02
        • 2017-08-20
        • 1970-01-01
        • 2015-02-10
        相关资源
        最近更新 更多