Symfony3:如何使用PATCH方法将布尔值更新为false

Rou*_*ubi 6 symfony

我有一个很大的实体和一个大的形式.更新我的实体时,我只通过ajax调用渲染表单的一部分.在客户端,我使用Jquery和html5 FormData,所以我也可以在我的表单中发送文件.为了确保在进程中未呈现的字段不会设置为null,我正在使用PATCH方法.

因此,当请求中不存在某个字段时,Symfony 就会保留该字段.

但是当我更新的字段是一个设置为true的布尔值(呈现的aa复选框)并且我想将其设置为false时,它不会在请求中传递,因此我的更新被忽略.

是否有一种简单的方法可以强制取消选中复选框以显示在请求中?

编辑
我找到了一种强制未选中复选框出现在请求中的方法,这要感谢Felix Kling对此问题的评论:

$("input:checkbox:not(:checked)").each(function() {
    formData.set($(this).attr('name'), formData.has($(this).attr('id')) ? '1' : '0');
});  
Run Code Online (Sandbox Code Playgroud)

不幸的是,由于Symfony的行为,这并没有解决我的问题:
- 当使用PUT时,如果请求中出现布尔字段,则无论其值如何(即使它为"0"或"false"),它都设置为true .
- 使用PATCH方法时,将忽略请求中未出现的字段.

可以用DataTransformer解决吗?(我从来没用过它)

Igo*_*vić 5

完全正确,如果方法是PATCH,Symfony将忽略它,因为Request Handler中这一行

$form->submit($data, 'PATCH' !== $method);
Run Code Online (Sandbox Code Playgroud)

现在,我通常会建议您使用PUT请求(如果可以选择的话),但是如果不是,那么FormInterface::submit($submittedData, $clearMissing = true)您要使用的第二个参数。

“正确”的方式很可能是使自己实现Symfony\Component\Form\RequestHandlerInterface这将迫使$clearMissingtrue

另外,方法要容易得多,但可能不适用于所有用例:$form->submit()直接使用。

如果您具有以下代码:

$form->handleRequest($request);
Run Code Online (Sandbox Code Playgroud)

你可以做:

$form->submit($request->get($form->getName()), true);
Run Code Online (Sandbox Code Playgroud)

您也可以省略第二个参数,因为true它是默认值


Rou*_*ubi 1

这是一个可行的解决方案,可以改进

为了强制未选中的复选框出现在请求中,感谢 Felix Kling 对这个问题的评论,我在 ajax 请求之前添加了这个 js :

$("input:checkbox:not(:checked)").each(function() {
    formData.set($(this).attr('name'), formData.has($(this).attr('id')) ? '1' : '0');
});  
Run Code Online (Sandbox Code Playgroud)

然后,在 Symfony 方面,我必须重写 BooleanToStringTransformer 行为,该行为返回true任何字符串且false仅返回 null 值。对最后一行进行更改,如果该值与为true定义的值(默认为“1”)不匹配,我们现在返回false 。因此,如果表单返回的值为“0”,我们将得到false,正如预期的那样。

public function reverseTransform($value)
{
    if (null === $value) {
        return false;
    }

    if (!is_string($value)) {
        throw new TransformationFailedException('Expected a string.');
    }

    return ($this->trueValue === $value); // initially: "return true;" 
}
Run Code Online (Sandbox Code Playgroud)

按照文档,我制作了自己的 DataTransformer 以及自定义AjaxCheckboxType

不幸的是,Symfony 似乎同时使用了两个DataTransformers(我的和原来的),一个接一个,所以它不起作用。TextType在他们扩展的文档中CheckboxType,这必须解释我遇到的问题。

我最终将整个内容复制并粘贴CheckboxType class到我自己的 AjaxCheckboxType 中,仅更改 DataTransformer 的调用才能使用我的。

一个更好的解决方案是完全覆盖 DataTransformer,但我不知道如何。