Symfony 5 - javascript XMLHttpRequest 发送的表单数据对象未在控制器中提交

Symfony5 - formData object send by javascript XMLHttpRequest not Submited in controller

我正在尝试在 canvas 上保存图像(保存它掉落到的位置、它的来源...等)。为了实现这一点,每个图像都被认为是一个对象,该对象具有一个 saveObject 方法,该方法将 POST 一个 formData 对象向 Symfony5 控制器抛出一个 XMLHttpRequest,它将以 symfony 形式接收 formData。 symfony 表单绑定到表示 canvas 中对象的实体,并且应该在提交时将表单数据内容保存到数据库中。

我面临的问题是控制器似乎没有考虑提交的表单。 我检查过:formData 对象确实包含 XMLHttpRequest 之前的所有数据,但在控制器端,所有字段似乎都设置为 null。

这是 saveObject 方法:

    saveObject() {
        console.log("In saveObject");
        var xhr = new XMLHttpRequest();
        var FD  = new FormData;

        // set FormData values
        for (name in this) {
            if (name === 'album_id') {
                FD.append(name, this.parent_album);
            } else {
                FD.append(name, this[name])
            }
        }

        //used to check if FD contains the data it is supposed to         
        for (var key of FD.entries()) {
            console.log(key[0] + ', ' + key[1]);
        }

        xhr.open('POST', '/edit/storeObjects/');

        xhr.send(FD);

        xhr.onload = function () {
            if (xhr.status != 200) {
                alert(`Error ${xhr.status}: ${xhr.statusText}`);
            } else {
                console.log("subission ok");
                console.log(xhr.response);
            }
        }
    }

这是接收请求的控制器:

     /**
     * @Route ("/edit/storeObjects/", name="save_object")
     */
    public function saveObj(Request $request, EntityManagerInterface $em, UploaderHelper $uploaderHelper, SluggerInterface $slugger)
    {
        $albumObj = new AlbumObjects();
        $user = $this->getUser();

        $form = $this->createForm(SaveObjectFormType::class);
        $form->handleRequest($request);

        if ($request->isMethod('POST')) {
            $form->submit($request->request->get($form->getName()));

            if ($form->isSubmitted() && $form->isValid()) {

                /** @Var AlbumObjects $albumObj * */
                $albumObj = $form->getData();

                if (true == $form['destImg']->getData()) {
                    $destImg = $form['destImg']->getData();
                    $user_dest = $user->getOwneravatar();
                    $newFilename = $uploaderHelper->uploadProfilePicture($user_dest, $destImg, $slugger);
                    $albumObj->setDestImg($newFilename);
                }
                $em->persist($albumObj);
                $em->flush();

                return $this->json([
                    'saveStatus' => 'Saved'
                ]);
            }
        }

            return $this->json([
                'saveStatus' => 'Not saved',
                'albumObj' => $albumObj
            ]);
    }

我显然做错了什么,如果能提示我遗漏了什么,我将不胜感激

我大部分都错了,但在朋友的一些建议下,现在可以正常工作了,所以我post告诉她我所做的修改,以防其他人遇到同样的问题.

首先,由于 symfony 表单中包含的 csrf 保护,表单未被验证或提交。 为了解决这个问题,我得到的建议非常有效,而不是将 post 数据发送到表单的普通 xmlhttprequest :首先执行 get 请求,然后从 csrf 表单中获取 return令牌。

然后在 javascript 中创建 formData 对象时,需要将表单的名称属性作为参数。

最后,虽然图像已发送到控制器,但并未在控制器中提交(我还检查了 enctype 是否正确)。我通过直接在 Request 对象中获取图像来解决这个问题。这个解决方案虽然“感觉不对”

这就是我更改 javascript xmlhttprequest 部分的方式:

   saveObject() {

    let xhr = new XMLHttpRequest();
    xhr.open('GET', '/edit/storeObjects/');
    xhr.send();

    xhr.onload = function () {
        if (xhr.status !== 200) {
            alert(`Error ${xhr.status}: ${xhr.statusText}`);
        } else {
            var formName = document.createElement('form');
            formName.setAttribute('name', JSON.parse(xhr.response)['formName']);

            var fD  = new FormData(formName);
            var attrListe = ['parentAlbum','pageNumber','type','dx','dy','dwidth','dheight','sx','sy','swidth','sheight','destImg','containedText','fontSize', 'fontType','fontColor','textMaxWidth','textLineHeight','album']

            attrListe.forEach(attrName => {
                if (attrName == 'destImg') {
                    var file = this.dataURLtoFile(this.destImg, 'img');
                    fD.append(attrName, file);
                } else {
                    fD.append(attrName, this[attrName])
                }
            });
            fD.append('_token', JSON.parse(xhr.response)['token']);

            for (var value of fD.entries()) {
                console.log(value[0] + ': ' + value[1]);
            }

            let xhrPost = new XMLHttpRequest();
            xhrPost.open('POST', '/edit/storeObjects/');
            xhrPost.send(fD);

            xhrPost.onload = function () {
                if (xhrPost.status !== 200) {
                    alert(`Error ${xhrPost.status}: ${xhrPost.statusText}`);
                } else {
                    console.log("Object Saved")
                }
            }
        }
    }.bind(this)
}

这里是对控制器的修改:

public function saveObj(Request $request, EntityManagerInterface $em, UploaderHelper $uploaderHelper, SluggerInterface $slugger)
{
    $user = $this->getUser();

    $form = $this->createForm(SaveObjectFormType::class);
    $form->handleRequest($request);

    if ($request->isMethod('POST')) {
        $form->submit($request->request->all());

        if ($form->isSubmitted() && $form->isValid()) {

            /** @Var AlbumObjects $albumObj * */
            $albumObj = $form->getData();

            //Check if the image field contains a file and if it does process it
            if ($request->files->get('destImg')) {
                $dest_Img = $request->files->get('destImg'); 
                $user_dest = $user->getOwneravatar();
                $newFilename = $uploaderHelper->uploadProfilePicture($user_dest, $dest_Img, $slugger);
                $albumObj->setDestImg($newFilename);
            }
            $em->persist($albumObj);
            $em->flush();

            return $this->json([
                'saveStatus' => 'Saved',
            ]);
        }
    }

        return $this->json([
            'formName' => $form->createView()->vars['name'],
            'token' => $form->createView()->children['_token']->vars['value']
        ]);
}