没有实体的复杂形式的表单集合永远不会验证

时间:2015-07-03 15:38:12

标签: forms symfony twig

我目前正在处理“过滤器”表单,以增加用户在项目列表上应用过滤器的可能性。我面临的问题是,一旦提交表单,控制器就会认为表单是空的并且无效。

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

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

日志中既没有错误也没有警告。 GUI在过滤器的字段上返回错误:

  

此值无效。

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

这是该项目的布局:

  • 包含一个选择输入和一个文本输入的FormType
  • 另一个在集合中实现前者的FormType
  • 控制器,实例化并使用表单
  • 第二个FormType的Twig视图,
  • 和最后的Twig页面

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

我已经倾倒了我所能做的一切,没有什么是真正有趣的。我甚至不确定内核是否理解/正确地“链接”用户执行的提交和控制器创建的表单。

对此的任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:1)

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

解决这个问题的最佳方法是将默认表单呈现作为起点,不要做任何自定义HTML,直到您完全确定需要自定义模板为止。执行此操作时,请检查默认模板以查看元素名称的构建方式,并遵循完全相同的命名,甚至更好地重用基本模板(通过扩展块和调用parent()和/或使用block功能)。