Bonjour à tous,

J'ai mis en place une drop-zone indépendante pour des images, celle-ci n'est pas un contrôle de formulaire...

La partie javascript marche parfaitement, j'ai bien ma liste d'images draguées qui est envoyée au controller Symfony.

Je dois traiter ensuite chaque image en passant par un service "PictureService" qui était à l'époque destiné à traiter des fichiers "UploadedFile".

Le problème est que je ne sais pas comment adapter chaque fichier image pourqu'il soit traité par le service, dans le code ci-dessous, je crée un nouvel objet Uploadedfile pour chaque image mais je n'arrive pas à récupérer les propriétés de chaque objet dans le tableau...

Se pourrait t'il que mon objet JSON ne soit pas bon ? Voici ce que m'affiche le getContent() :

{#748
  +"files": {#745
    +"0": {#744}
    +"1": {#746}
    +"2": {#747}
  }
  +"galerieId": "81"
}

Comme vous le voyez, les propriétés de chaque image sont inaccessibles, par contre je peux accéder à la propriété "galerieId" sans problème...

Je pense qu'il y a une erreur dans l'envoi du fichier "files" dans la requête Ajax (faut-il vraiment utiliser stringify pour un objet ?).

D'autre-part, faut-il créer un nouvel objet "Uploadedfile" pour chaque image comme je tente de le faire ou bien exite il une autre méthode qui permettrait le traitement dans le service cité ? (J'ai essayé en changeant Uploadedfile pour File, ça ne marche pas non plus)

Merci d'avance pour votre expertise

drop-area.js:

const handleDrop = (e) => {
  const dataTransfer = e.dataTransfer;
  const files = dataTransfer.files;
  const listeImages = [...files];
  console.log(listeImages);

  //Affichage des détails des images en tableau en cours d'importation
  const tableauDetails = document.querySelector(".tableau-details-images");
  tableauDetails.innerHTML = "";

  tableauDetails.insertAdjacentHTML(
    "afterbegin",
    `<span>${listeImages.length} images sélectionnées : </span>`
  );
  let i = 1;
  listeImages.forEach((img) => {
    tableauDetails.insertAdjacentHTML(
      "beforeend",
      `<div class="details-image">${i}. ${img.name} ${readableFileSize(
        img.size
      )} ${img.type}</div>`
    );
    i++;
  });

  //envoi de la liste d'images vers le controller Galeries de symfony
  const envoiListeImages = async () => {
    const galerie = document.querySelector(".container-galerie");
    let galerieId = galerie.dataset.id;

    try {
      const response = await fetch(`/admin/galeries/importer-images`, {
        method: "POST",
        headers: {
          "X-Requested-with": "XMLHttpRequest",
          "Content-Type": "application/json;charset=UTF-8",
        },
        body: JSON.stringify({ files, galerieId }),
      });
      const data = await response.json();
      console.log(data);
    } catch (error) {
      console.error("Errors : ", error);
    }
  };
  envoiListeImages();
};

importer-imagesController.php:

#[Route('importer-images', 'importer_images', methods: ['POST'])]
    public function importerImages(Request $request, EntityManagerInterface $em, PictureService $pictureService): Response
    {
        if ($request->isXmlHttpRequest()) {
            $postData = json_decode($request->getContent());
            // dd($postData);
            $galerie = $postData->galerieId;
            // dd($galerie);
            $listeImages = $postData->files;
            // dd($listeImages);
            foreach ($listeImages as $image) {
                $image = new UploadedFile("", $image, $image->name, $image->type);
                $folder = 'images';
                $fichier = $pictureService->add($image, $folder, 300, 300);

                $img = new Images();
                $img->setName($fichier);
                $galerie->addImage($img);
            }
            $em->persist($galerie);
            $em->flush();

            $this->addFlash('success', 'La nouvelle galerie d\'images a été actualisée dans la base.');
            return new JsonResponse('Réponse en json');
        }
        return new JsonResponse(['error' => 'Cet appel doit être effectué via AJAX.'], Response::HTTP_BAD_REQUEST);
    }

8 réponses


Hello :)

Alors dans ton cas il ne faut pas utiliser de json pour les files, mais un tableau de json:

{#748
  +"files": [
    +"0" => {#744}
    +"1" => {#746}
    +"2" => {#747}
  ]
  +"galerieId": "81"
}

Un json ce n'est pas fait pour etre parcouru mais pour récupérer un élément spécifique à partir d'une clé, alors si il y a 1, 2, 3... c'est un tableau ^^

Merci Popotte pour ta réponse

J'avais pensé à convertir mon tableau grâce au spread operator dans le js, j'ai donc maintenant un tableau Json exactement comme celui que tu m'as envoyé mais pour pouvoir l'exploiter en tant qu'objet dans le controller je suppose qu'il faut le désérialiser ?

J'ai essayé de le faire en injectant le "serializerInterface" dans les paramètres de ma fonction mais il ne reconnaît pas la commande "serialize" ni "deserialize" malgré que les Use soient importés correctement... Que fais-je mal ?

De rien ;)

Mmmh plus simple d'utiliser les fonctionnalité de PHP basiques: json_encode et json_decode

Bonjour Popotte

Que je fasse n'importe quoi le tableau d'objet ne retourne que des chiffres précédés d'un "#", j'ai bien les index dans le tableau mais pas les keys/values, inexploitable !
Par contre j'ai bien la variable "galerieId" de disponible en tant qu'objet, à n'y rien comprendre...
On dirait que le tableau de valeursn'est pas convertit malgré le couple classique stringify en js et json_decode en php...

La console du navigateur donne ceci grâce au spread (tout est normal) :

liste images : 
Array(4) [ File, File, File, File ]
​
0: File { name: "Look2-111bbbb-2vb.jpg", lastModified: 1718454649514, size: 3782549, … }
​​
lastModified: 1718454649514
​​
name: "Look2-111bbbb-2vb.jpg"
​​
size: 3782549
​​
type: "image/jpeg"
​​
webkitRelativePath: ""
​​
<prototype>: FilePrototype { name: Getter, lastModified: Getter, webkitRelativePath: Getter, … }
​
1: File { name: "Look2-150b-2.jpg", lastModified: 1718454649546, size: 3964591, … }
​
2: File { name: "Look2-265.jpg", lastModified: 1718454649925, size: 12624466, … }
​
3: File { name: "Look2-292vvv-3.jpg", lastModified: 1718454649942, size: 556375, … }
​
length: 4
​
<prototype>: Array []
drop-images.js:28:11

Par contre une fois utilisé json_decode en false, null ou true dans le controller ($postData = json_decode($request->getContent(),false);

J'ai toujours ceci :

{#747
  +"listeImages": array:4 [
    0 => {#743}
    1 => {#744}
    2 => {#745}
    3 => {#746}
  ]
  +"galerieId": "201"
}

A noter que les valeurs entre "{}" ne sont pas accessible par click (expansion)

Ca serait pas le fait que les ligne de données soient préfixées par "FILE" ?

Ca doit etre bête mais je m'arrache les cheveux ...

C'est normal, en gros tu accèdes à chaque élément depuis un forEach ou un map, enfin une boucle

foreach ($listeImages as $image) {
    // et ici tu a accès a chaque File
    dump($image->name);
}

dd($listeImages);

Bonjour Popotte

Toujours pareil : impossible de lire les propriétés du tableau !

Si je fais :

foreach ($listeImages as $image) {  
    dd($image->name);
}

Il me renvoie : "Warning: Undefined property: stdClass::$name", on en revient toujours au même, le tableau ne contient pas les données escomptées, seulement des "#" suivis de numéros, sans possibiliter d'accéder aux propriétés...

Voir ici :

{#746
  +"listeImages": array:3 [
    0 => {#743}
    1 => {#744}
    2 => {#745}
  ]
  +"galerieId": "201"
}

En principe il devrait y avoir les keys/values dans les crochets non ?

J'ai tranformé en formData : aucune différence
J'ai utilisé tous les json_decode(true,false,null) : aucune différence

J'ai déjà fait des milliers d'envois Ajax de ce genre vers des controllers Symfony, c'est la première fois que ça foire, à chaque fois j'utilise les couples JSON.stringify ou formData/Json_decode().

Là le tableau n'est pas correct, j'ai forcément oublié un détail...
J'ai fait un e.preventDefault partout où nécessaire aussi...
Je pencherai plutôt sur une erreur dans le js ...

Je sèche...

Voici le code actualisé :

//envoi de la liste d'images vers le controller Galeries de symfony
  const envoiListeImages = async (e) => {
    e.preventDefault();
    const galerie = document.querySelector(".container-galerie");
    let galerieId = galerie.dataset.id;

    const formData = new formData();
    formData.append("listeImages", JSON.stringify(listeImages));
    formData.append("galerieId", JSON.stringify(galerieId));

    try {
      const response = await fetch(`/admin/galeries/importer-images`, {
        method: "POST",
        headers: {
          "X-Requested-with": "XMLHttpRequest",
          "Content-Type": "application/json; charset=UTF-8",
        },
        body: formData,
      });
      const data = await response.json();
      console.log("postData : ", data);
    } catch (error) {
      console.error("Errors : ", error);
    }
  };
  envoiListeImages();
};

Bon , j'ai trouvé la solution, il fallait itérer sur le tableau listeImages dans le form data :

    //Création du formData
    const formData = new FormData();
    //Traitement du tableau d'images
    listeImages.forEach((file) => {
      formData.append("listeImages[]", file);      
    });

Merci pour ton aide

Merci pour ta réponse ,vous mavez boucaup aider

Kodi