没有实体的叠层形式的形式集合从不验证

Form collection of imbricated form without entity never validates

我目前正在开发 "Filters" 表单,以增加用户在项目列表上应用过滤器的可能性。我面临的问题是,一旦提交了表单,控制器就认为该表单为空且无效。

转储 $form->getData() 返回的内容显示如下:

array(1) { ["filters"]=> array(0) { } }

日志中既没有错误也没有警告。 GUI returns 过滤器字段错误:

This value is not valid.

但是,如果我修改 Twig 小部件以将 select 的 ID 更改为其他任何内容,我将不再获得无效值,但表单的数据仍然是一个空数组。

这是这个项目的布局:

FilterSearchType.php

namespace NetDev\CoreBundle\Form\Helpers;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\FormBuilderInterface;
use NetDev\CoreBundle\Form\Helpers\FilterType;

class FilterSearchType extends AbstractType {
    public function buildForm(FormBuilderInterface $builder, array $options) {
        $builder
            ->add('filters', 'collection', array('type' => new FilterType($options['entity']), 'allow_add' => true,
                                                 'allow_delete' => true, 'by_reference' => false))
            ->add('search', 'submit');
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver) {
        $resolver->setDefaults(array('filters' => [],
                                     'entity' => null));
    }

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

FilterType.php

<?php

namespace NetDev\CoreBundle\Form\Helpers;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\FormBuilderInterface;

class FilterType extends AbstractType {
    public function __construct($entity) {
        $this->model = $entity;
    }

    public function buildForm(FormBuilderInterface $builder, array $options) {
        $builder
            /*getFilters returns something like that:
             * ['Column A' => 'column_a', 'Column B' => 'column_b', ...]
             */
            ->add('column_name', 'choice', array('choices' => $this->model->getFilters(true)))
            ->add('search_value', 'text')
            ;
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver) {
    $resolver->setDefaults(['column_name' => '',
                            'search_value' => '']);
    }

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

下面是从控制器向 Twig 提供表单的方式:

RoutesController.php

class RoutesController extends Controller {
    public function indexAction($page = 1, Request $request) {
        $em = $this->getDoctrine()->getManager();

        $orderBy = $request->query->get('orderBy');
        $orderType = $request->query->get('orderType');

        $form = $this->createForm(new RouteManagerType($em), null, array('orderBy' => $orderBy,
                                                                     'orderType' => $orderType));
        $filterForm = $this->createForm(new FilterSearchType(), null, array('entity' => new Route()));

        if ($request->isMethod('POST') && $filterForm->handleRequest($request)->isValid()) {
            // Never reached, $filterForm is always marked as invalid
            $formData = $filterForm->getData();

            var_dump($formData);
            exit();

            if (!empty($formData['filters']) && count($formData['filters'])) {
                if (empty($formData['action'])) $formData['action'] = 'filter';

                $form = $this->createForm(new RouteManagerType($em), null,
                                          array('orderBy' => $orderBy,
                                                'orderType' => $orderType,
                                                'filters' => $formData['filters']));
            }
    }

Twig 小部件:filter_search.html.twig

{% block netdev_filter_widget %}
  {% spaceless %}
  {{ form_errors(form) }}
  <div class="form-group">
    <div class="input-group">
      <select {{ block('widget_attributes') }} class="form-control" id="search_column">
        {% for group_label, choice in form.column_name.vars.choices %}
          <option value="{{ choice.value }}" {{ block('attributes') }}>{{ choice.label }}</option>
        {% endfor %}
      </select>
      <div class="input-group-addon">contains</div>
      <input type="text" class="form-control" id="search_criteria" placeholder="search"/>
    </div>
  </div>
  {% endspaceless %}
{% endblock %}

我几乎倾尽所有,但没有什么是真正有趣的。我什至不确定内核是否理解/正确 "links" 用户执行的提交以及控制器创建的表单。

如有任何帮助,我们将不胜感激。

好的,所以问题是如果你自己渲染,你应该非常清楚 HTML 中渲染的名称正是后端所期望的,否则你会遇到这样的问题。

解决这个问题的最佳方法是以默认表单呈现为起点,在您完全确定需要自定义模板之前不要进行任何自定义 HTML。当你这样做时,检查默认模板以查看元素的名称是如何构建的,并遵循完全相同的命名,或者更好的是,尽可能重用基本模板(通过扩展块和调用 parent() and/or使用 block 函数)。