I am trying to save images when dropped over a canvas (saving the position it is dropped to, it source ...etc). To acheive this each image is considered an object that has a saveObject methode that will POST a formData object threw an XMLHttpRequest to a Symfony5 controller, that will receive the formData in a symfony Form. The symfony form is binded to the the entity representing the objects in the canvas, and should save the formData content to the database on submit.
The problem I am facing is that the controller seem's not to consider the form as submitted. I have checked : the formData object does contain all the data before the XMLHttpRequest, but on the controller side all the fields seem to be set to null.
this is the saveObject methode :
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);
}
}
}
And this is the controller receiving the request :
/**
* @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
]);
}
I am obviously doing something wrong, and would appreciate a hint to what it is I'm missing
I had most of this wrong but with some advice from a friend and some time it is now working, so I am posting her the modifications I have made in case anybody else is having the same issue.
First the form wasn't validated nor submitted because of the csrf protection included in symfony forms. To go around this the advice I got and that worked pretty well was instead of a plain xmlhttprequest to post the data to the form : do first a get request and on this get return from the form the csrf token.
Then when creating the formData object in javascript it need's to take as parameter the form's name attribute.
Finally, the image wasn't being submitted in the controller though it was sent to the controller (also I checked the enctype was correct). I worked around this by getting the image directly in the Request object. This solution though doesn't "feel right"
so this is how I changed the javascript xmlhttprequest part :
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)
}
And here are the modifications to the controller :
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']
]);
}