未考虑Symfony2表单未选中复选框,为什么?

时间:2016-02-19 10:27:50

标签: forms symfony checkbox

当我发送带有未选中复选框的表单时,如果相关实体属性等于true,则它不会更改为false

另一种方式(使用选中的复选框发送表单时将属性设置为true)可以正常工作,以及保存其他字段的所有表单。

以下是我如何构建表单并声明相关属性:

// --- Form creation function EntityType::buildForm() ---
$builder->add('secret', 'checkbox', array( 'required' => false ));

// --- Entity related property, Entity.php file ---
/** @ORM\Column(name="secret", type="boolean") */
protected $secret;

编辑:问题出现是因为表单是使用一个PATCH请求提交的。

在Symfony中,请求处理程序使用以下行调用Form::submit方法:

$form->submit($data, 'PATCH' !== $method);

因此,在PATCH请求的情况下Form::submit $clearMissing参数设置为false,从而将未发送的字段保留为旧值。< / em>的

但我不知道如何解决这个问题。如果我在未选中复选框的情况下明确地将JSON {secret: false}传递给Symfony框架,它会将其解释为"false"字符串并将其视为真值,因此请考虑选中复选框... < / em>的

NB。我有完全相同的问题,其中包含一个使用choice字段类型multipleextendedtrue)链接到一个复选框的数组Doctrine Simple Array属性:只要给定复选框一经检查发送一次,就不可能将相关属性设置为false并随后提交unchecked

6 个答案:

答案 0 :(得分:4)

问题出现是因为表单是使用一个PATCH请求提交的。

这导致开放this Symfony issue

如上所述,一种解决方法是在未选中复选框(而不是不发送任何内容)时明确发送特定保留值(例如字符串&#39; __ false&#39;),并将此值替换为&#39 ;空&#39;使用表单类型中的自定义数据转换器:

// MyEntityFormType.php -- buildForm method
$builder->add('mycheckbox', ...);
$builder->get('mycheckbox')
    ->addViewTransformer(new CallbackTransformer(
        function ($normalizedFormat) {
            return $normalizedFormat;
        },
        function ($submittedFormat) {
            return ( $submittedFormat === '__false' ) ? null : $submittedFormat;
        }
    ));

选择&#39;的情况字段不能以同样的方式解决。它实际上是Symfony的一个错误,在this issue处理。

答案 1 :(得分:2)

您使用的是什么版本的Symfony?

p{ margin:0; } vendor/symfony/symfony/src/Symfony/Component/Form/Form.php中,应该存在一些专门针对您所撰写的情况的代码:

Form::submit()

位于525-534行。你能检查一下这个吗?

另一个导致是自定义表单订阅者,它不能完全按预期工作 - 通过覆盖提供的值。

答案 2 :(得分:2)

上述情况并非如此,对我没有帮助。 所以,我正在使用这个......

<强>解释

&#34; PATCH&#34;解决此问题方法被使用,是为了添加额外的隐藏&#34;时间戳&#34;表单类型中的字段,并将其放在twig文件中的issue复选框旁边。这需要与复选框一起传递,这肯定会改变 - 时间戳会改变。

接下来是使用PRE_SUBMIT事件并等待表单字段到达,如果没有设置,我会手动设置...工作正常,我不介意额外的代码...

<强> FormType

$builder
...
->add('some_checkbox')
->add('time_stamp', 'hidden', ['mapped' => false, 'data' => time()])
...

<强>枝条

{{ form_widget(form.time_stamp) }}
{{ form_widget(form.some_checkbox) }}

构建器中的PRE_SUBMIT事件

$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) use($options) {

    $data = $event->getData();
    $form = $event->getForm();

    if (!$data) {
        return;
    }
    /* Note that PATCH method is added as an option for "createForm" 
     * method, inside of your controller 
    */       
    if ($options["method"]=="PATCH" && !isset($data['some_checkbox'])) {
        $form->getData()->setSomeCheckbox(false);//adding missing checkbox, since it didn't arrive through submit.. grrr
    }            
});

答案 3 :(得分:1)

可能是因为您的架构不需要该字段。您可以使用以下选项为复选框提供默认值:

$builder->add('secret', 'checkbox', array(
  'required' => false,
  'empty_data' => false
));

请参阅herehere

答案 4 :(得分:0)

此解决方案对我有用。

MapState

答案 5 :(得分:0)

另一种可能性是添加一个隐藏的元素,并使用Javascript来实现。在使用没有JavaScript的浏览器的用户中,有0.1%的人会失败。 这是多个复选框FormType元素的简单示例:

            ->add('ranges', ChoiceType::class, array(
            'label'   => 'Range',
            'multiple' => true,
            'expanded' => true,
            'choices' => array(
                null => 'None',
                'B1' => 'My range',
            )
        ))

<script>
$(document).ready(function() {
       function updateDynRanges(object) {
            if (object.prop("checked")) {
                document.getElementById('ranges_0').checked = 0;
            } else {
                document.getElementById('ranges_0').checked = 1;
            }
        }
 // On page onload
        $('#ranges_1').change(function() {
           updateDynRanges($(this));
        });
        updateDynRanges($('ranges_1'));
}
</script>

如果经过测试,您可以在第二个复选框中添加“ visible:false”。

树枝模板:

 {{ form_label(form.dynamicRanges) }}<br>
 {{ form_widget(form.dynamicRanges[1]) }}
 <div class="hidden">{{ form_widget(form.ranges[0]) }}</div>

看起来像一个丑陋的解决方法,但我只是想与其他丑陋建议的解决方法竞争,在这种情况下,大多数情况是更新了树枝模板。