Symfony2表单提交无效的布尔值

时间:2013-08-07 11:53:14

标签: forms rest symfony checkbox boolean

我对Symfony(v 2.3.2)表格有一个奇怪的问题。没有关系,这是非常简单的形式。我还应该注意,此表单仅用于REST API。

所以我有一个已发布的字段(布尔值)。在实体上,默认设置为false。

在更新时,REST API客户端发送正确的PUT请求...&[entity]published=0&...。该值也在表格参数中的Symfony profiler中显示。

但是我注意到数据库中的实际值设置为true(或者是1,因为它的tinyint)。

因此,为了找出问题所在,我在$form->submit($request);

之后添加了throw语句

throw new \Exception(sprintf('Request: %s, form: %s', $request->get('entity')['published'], $form->get('published')->getData()));

throw new \Exception(sprintf('Request: %s, form: %s', $request->get('entity')['published'], $form->getData()->getPublished()));

异常消息显示:Request: 0, form: 1。这意味着在submit方法的某处,字符串值'0'将转换为1。

该字段由$builder->add('published', 'checkbox', [ 'required' => false ])

构成

此外,我注意到奇怪的事情,这可能是相关的。在Symfony分析器,面板请求中,我收到错误:Warning: json_encode(): Invalid UTF-8 sequence in classes.php line 3758,我没有发送任何奇怪的字符 - 只是单词“test”。

3 个答案:

答案 0 :(得分:5)

您不应在API中使用复选框表单类型,0并不代表错误。

你应该实现一个新的布尔表单类型,它转换1,' 1'并且真实,其他一切都是假的(例如)。

以下是一个示例:https://gist.github.com/fsevestre/abfefe0b66e5f5b24c60

答案 1 :(得分:2)

进一步调查发现,典型的HTML表单复选框仅在选中时发送给服务器。所以我假设将值设置为0 | false | off会使其工作,就像将它设置为true一样。

因此,如果您将表单窗口小部件设置为键入复选框,则如果要将其设置为false,请不要在请求中发送复选框。就我而言,它看起来像这样:

Array
(
    [entity] => Array
    (
        [id] => 73
        [_token] => d63dad39ea458f7d3c7ae5dbea10c325cb9ee93d
    )
)

否则发送任何内容,0,false,off也会起作用

Array
(
    [entity] => Array
    (
        [id] => 73
        [published] => 1|0|false|on|off
        [_token] => d63dad39ea458f7d3c7ae5dbea10c325cb9ee93d
    )
)

答案 2 :(得分:0)

使用PUT时,这有点问题...... 我通过在所有解决此问题的表单中添加订阅者来解决这个问题(此代码也解决了使用PUT而不填充所有数据的问题):

class RestFormSubscriber implements EventSubscriberInterface {

    /**
     * {@inheritdoc}
     */
    public static function getSubscribedEvents()
    {
        return array(FormEvents::PRE_SUBMIT => "preSubmit");
    }

    /**
     * Remove null fields on update
     * Fixes boolean value
     * @param FormEvent $event
     */
    public function preSubmit(FormEvent $event)
    {
        $form = $event->getForm();
        $data = $event->getData();

        $isPUT = strtoupper($form->getConfig()->getMethod()) == "PUT";

        $accessor = PropertyAccess::createPropertyAccessor();
        foreach ($form->all() as $name => $child) {
            if ($isPUT && !isset($data[$name])) {
                $form->remove($name);
                continue;
            }
            if(is_bool($accessor->getValue($form->getData(), $name))) {
                $val = $data[$name];
                $data[$name] = ($val=="true")||($val=="1")||($val=="on");
            }
        }
        $event->setData($data);
    }
}