Partage
  • Partager sur Facebook
  • Partager sur Twitter

[Symfony 4] Upload de fichier

Sujet résolu
    13 novembre 2019 à 17:09:38

    Bonjour,

    je continue ma formation sur Symfony 4, et je rencontre un soucis avec l'envoi de fichier. Voici les détails :

    J'ai 2 entités, album et musique. Les deux sont liés, 1 album pouvant avoir plusieurs musiques. J'aimerais que mon administrateur puisse modifier les données en base ainsi que la pochette de l'album ou l'extrait et qu'il n'ait qu'une seule page pour modifier le tout. J'arrive bien à afficher un formulaire avec mes données "album" et mes données "musique", j'arrive bien à permettre la modification de la pochette, mais ça coince sur l'extrait (le nom de ma table en base est 'url'), ou j'ai cette erreur : 

    Argument 1 passed to App\Service\FileUploaderMP3::upload() must be an instance of Symfony\Component\HttpFoundation\File\UploadedFile, instance of Doctrine\ORM\PersistentCollection given, called in /Library/WebServer/Documents/projets/musiconaute/src/Controller/AlbumController.php on line 65

    Voici mon AlbumController pour la partie qui nous intéresse :

    public function edit(Request $request, Album $album, FileUploaderAlbum $fileUploader, FileUploaderMP3 $fileUploaderMp3)
        {
            $form = $this->createForm(AlbumsType::class, $album);
    
            $form->handleRequest($request);
    
            if ($form->isSubmitted() && $form->isValid()) {
                $albumsFile = $form['couverture']->getData();
                if ($albumsFile) {
                    $albumFileName = $fileUploader->upload($albumsFile);
                    $album->setCouverture($albumFileName);
                }
                $musiquesFile = $form['musiques']->getData();
                if ($musiquesFile) {
                    
                    $musiqueFileName = $fileUploaderMp3->upload($musiquesFile);
                    $musique->setURL($musiqueFileName);
                }
                // va effectuer la requête d'UPDATE en base de données
                $this->getDoctrine()->getManager()->flush();
    
            return $this->redirectToRoute('index');
            }
    
            return $this->render('admin/album/new.html.twig', array(
                'form' => $form->createView(),
            ));
    
            return new RedirectResponse($this->urlGenerator->generate('index'));
        }

    La ligne 65 correspond à la ligne $musiqueFileName = $fileUploaderMp3->upload($musiquesFile);

    Voici mon albumType :

    <?php
    
    namespace App\Form;
    
    use App\Entity\Album;
    use Symfony\Component\Form\AbstractType;
    use Symfony\Component\Form\FormBuilderInterface;
    use Symfony\Component\OptionsResolver\OptionsResolver;
    use Symfony\Component\Form\Extension\Core\Type\TextType;
    use Symfony\Component\Form\Extension\Core\Type\FileType;
    use Symfony\Component\Validator\Constraints\File;
    use Symfony\Component\Form\Extension\Core\Type\CollectionType;
    
    class AlbumsType extends AbstractType
    {
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder
                ->add('titre')
                ->add('couverture', FileType::class, [
                    'label' => 'Couverture de l\'album (en jpg ou en png)',
    
                    // unmapped means that this field is not associated to any entity property
                    'mapped' => false,
    
                    // make it optional so you don't have to re-upload the PDF file
                    // everytime you edit the Product details
                    'required' => false,
    
                    // unmapped fields can't define their validation using annotations
                    // in the associated entity, so you can use the PHP constraint classes
                    'constraints' => [
                        new File([
                            'maxSize' => '1024k',
                            'mimeTypes' => [
                                'image/*',
                                'application/jpg',
                                'application/jpeg',
                                'application/png',
                                'application/x-png',
                            ],
                            'notFoundMessage' => 'L\'image n\'a pas été trouvé',
                            'maxSizeMessage' => 'L\'image est trop grosse ({{ size }} {{ suffix }}). La taille maximum est de  {{ limit }} {{ suffix }}.',
                            'disallowEmptyMessage' => 'Il n\'est pas possible d\'envoyer un fichier vide',
                            'uploadNoFileErrorMessage' => 'L\'image n\'a pas été envoyée',
                        ])
                    ],
                ]);
                $builder->add('musiques', CollectionType::class, [
                'entry_type' => MusiquesType::class,
                'entry_options' => ['label' => false],
                'allow_add' => true,
            ]);
        }
    
        public function configureOptions(OptionsResolver $resolver)
        {
            $resolver->setDefaults([
                'data_class' => Album::class,
            ]);
        }
    }

    Je crois comprendre que l'argument que je lui passe n'est pas bon puisqu'il est de type "PersistentCollection", mais je ne comprends pas trop et je ne vois pas comment corriger cela.

    Est ce que quelqu'un pourrait m'aider s'il vous plait ?

    Merci d'avance :)


    • Partager sur Facebook
    • Partager sur Twitter
      13 novembre 2019 à 17:12:44

      Salut,

      question bête pourquoi essaies-tu d'entrer un fichier  ??

      • Partager sur Facebook
      • Partager sur Twitter
        13 novembre 2019 à 18:01:18

        Parce que c'est la demande. L'extrait est un fichier mp3, donc je dois envoyer un fichier et récupérer son lien.
        • Partager sur Facebook
        • Partager sur Twitter
          13 novembre 2019 à 20:16:05

          Bonsoir,

          Tu peux faire un dump $musiquesFile ?

          • Partager sur Facebook
          • Partager sur Twitter
            13 novembre 2019 à 20:57:53

            Bonsoir et merci pour ta réponse.

            Avec un dump($musiquesFile) placé sous mon 
            if ($musiquesFile) {
            j'obtiens ceci :

            AlbumController.php on line 64:
            PersistentCollection^ {#1257 ▼
              -snapshot: []
              -owner: null
              -association: array:15 [ …15]
              -em: EntityManager^ {#428 …11}
              -backRefFieldName: "album"
              -typeClass: ClassMetadata {#606 …}
              -isDirty: true
              #collection: ArrayCollection^ {#1256 ▼
                -elements: array:1 [▼
                  0 => Musique^ {#1280 ▼
                    -id: 5
                    -titre: "test"
                    -annee: "1980"
                    -auteur: "Alexane"
                    -body: "zaregfb"
                    -url: "KSoviet04Final-5dc1bef999997.mp3"
                    -blindtest: 1
                    -actif: 1
                    -visite: null
                    -album: Album^ {#604 ▼
                      -id: 1
                      -titre: "Nom de l'album"
                      -couverture: "1249373373Dragon_Jazz-5dc1b4fa32691.jpeg"
                      -musiques: PersistentCollection^ {#806 ▼
                        -snapshot: array:1 [ …1]
                        -owner: Album^ {#604}
                        -association: array:15 [ …15]
                        -em: EntityManager^ {#428 …11}
                        -backRefFieldName: "album"
                        -typeClass: ClassMetadata {#606 …}
                        -isDirty: false
                        #collection: ArrayCollection^ {#859 ▼
                          -elements: array:1 [▼
                            0 => Musique^ {#1280}
                          ]
                        }
                        #initialized: true
                      }
                    }
                    -support: 1
                  }
                ]
              }
              #initialized: true
            }

            Et du coup je pense que mon problème vient du fait que j'essaye de mettre à jour 'url', qui est dans la base musique, mais que je lui envoi un champ collection, du coup, il ne peut pas faire ce que je lui demande. Le truc c'est que je vois pas comment lui passer directement 'url' et non pas 'musiques' qui est une collection :/

            -
            Edité par Ewan 13 novembre 2019 à 21:05:30

            • Partager sur Facebook
            • Partager sur Twitter
              14 novembre 2019 à 18:34:53

              Tu peux te débrouiller pour récupérer l'url je pense, du genre $musiqueFile[0]->getUrl(), fais des dumps à chaque fois pour arriver à l'url.
              • Partager sur Facebook
              • Partager sur Twitter
                15 novembre 2019 à 13:53:59

                Jean_40 a écrit:

                Tu peux te débrouiller pour récupérer l'url je pense, du genre $musiqueFile[0]->getUrl(), fais des dumps à chaque fois pour arriver à l'url.


                un debugger peut etre pas mal :D
                • Partager sur Facebook
                • Partager sur Twitter
                  15 novembre 2019 à 14:26:17

                  Salut !

                  Qu'est-ce que tu as dans MusiqueType ?

                  Apparemment tu tentes de gérer une collection d'objets Musique comme un unique fichier uploadé…

                  • Partager sur Facebook
                  • Partager sur Twitter
                    18 novembre 2019 à 15:41:05

                    Désolée pour la réponse un peu tardive, un autre truc à gérer^^

                    Dans mon MusiquesType j'ai ceci :

                    <?php
                    
                    namespace App\Form;
                    
                    use [...]
                    
                    class MusiquesType extends AbstractType
                    {
                        public function buildForm(FormBuilderInterface $builder, array $options)
                        {
                            $builder
                                ->add('titre')
                                ->add('annee')
                                ->add('auteur')
                                ->add('body', TextareaType::class, array('attr' => array('class' => 'ckeditor'), 'required' => false,))
                                ->add('url', FileType::class, [
                                    'label' => 'Musique de l\'album (en mp3)',
                    
                                    // unmapped means that this field is not associated to any entity property
                                    'mapped' => false,
                    
                                    // make it optional so you don't have to re-upload the PDF file
                                    // everytime you edit the Product details
                                    'required' => false,
                    
                                    // unmapped fields can't define their validation using annotations
                                    // in the associated entity, so you can use the PHP constraint classes
                                    'constraints' => [
                                        new File([
                                            'maxSize' => '6024k',
                                            'mimeTypes' => [
                                                'audio/mpeg',
                                            ],
                                            'notFoundMessage' => 'Le mp3 n\'a pas été trouvé',
                                            'maxSizeMessage' => 'Le mp3 est trop gros ({{ size }} {{ suffix }}). La taille maximum est de  {{ limit }} {{ suffix }}.',
                                            'disallowEmptyMessage' => 'Il n\'est pas possible d\'envoyer un fichier vide',
                                            'uploadNoFileErrorMessage' => 'Le mp3 n\'a pas été envoyé',
                                        ])
                                    ],
                                ])
                                ->add('blindtest', ChoiceType::class, [
                        'choices'  => [
                            'Oui' => 1,
                            'Non' => 0,
                        ],
                    ])
                                ->add('actif', ChoiceType::class, [
                        'choices'  => [
                            'Oui' => 1,
                            'Non' => 0,
                        ],
                    ])
                                ->add('visite')
                                ->add('support', ChoiceType::class, [
                        'choices'  => [
                            'Oui' => 1,
                            'Non' => 0,
                        ],
                    ]);
                        }
                    
                        public function configureOptions(OptionsResolver $resolver)
                        {
                            $resolver->setDefaults([
                                'data_class' => Musique::class,
                            ]);
                        }
                    }
                    

                    Je pense en effet que mon soucis vient de l'utilisation d'une collection, que je ne maitrise pas :(

                    -
                    Edité par Ewan 18 novembre 2019 à 15:43:18

                    • Partager sur Facebook
                    • Partager sur Twitter
                      18 novembre 2019 à 16:15:26

                      Et peut-on voir la classe FileUploaderAlbum ?

                      • Partager sur Facebook
                      • Partager sur Twitter
                        18 novembre 2019 à 16:43:46

                        Oui c'est possible

                        <?php
                        
                        use Symfony\Component\HttpFoundation\File\Exception\FileException;
                        use Symfony\Component\HttpFoundation\File\UploadedFile;
                        use Symfony\Component\Intl\Intl;
                        
                        class FileUploaderAlbum
                        {
                            private $targetDirectory;
                        
                            public function __construct($targetDirectory)
                            {
                                $this->targetDirectory = $targetDirectory;
                            }
                        
                            public function upload(UploadedFile $file)
                            {
                                $originalFilename = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
                                $fileName = $originalFilename.'-'.uniqid().'.'.$file->guessExtension();
                        
                                try {
                                    $file->move($this->getTargetDirectory(), $fileName);
                                } catch (FileException $e) {
                                    // ... handle exception if something happens during file upload
                                }
                        
                                return $fileName;
                            }
                        
                            public function getTargetDirectory()
                            {
                                return $this->targetDirectory;
                            }
                        }

                        L'ajout de musique seul fonctionne, l'entrée se fait bien en base et le fichier est bien uploadé là ou il faut avec un changement de nom pour rajouter un id unique à la fin. L'ajout d'une musique se fait sur une page à part qui n'ajoute que la musique, pas l'album.

                        C'est vraiment à la modification, ou je veux qu'on puisse modifier album et musique sur la même page que ça coince. 

                        -
                        Edité par Ewan 18 novembre 2019 à 16:44:11

                        • Partager sur Facebook
                        • Partager sur Twitter
                          18 novembre 2019 à 16:54:11

                          Alors je confirme, c'est parce que tu gères une collection d'objets Musique comme si c'était un seul fichier uploadé, et ce n'est pas le cas  ;)

                          FileUploaderAlbum::upload attend en paramètre un objet UploadedFile, mais tu lui passes le contenu du champ musiques de AlbumsType, qui est défini comme une collection d'objets Musique. Il faut que tu boucles sur $musiquesFile pour vérifier s'il y a un fichier uploadé dans le champ url, et si oui c'est ce que contient ce champ qu'il faudrait uploader.

                          Edit

                          Ça y est, maintenant je ne reçois plus les notifications quand un sujet a des mises à jour…

                          -
                          Edité par Ymox 18 novembre 2019 à 16:54:48

                          • Partager sur Facebook
                          • Partager sur Twitter
                            18 novembre 2019 à 20:41:23

                            D'accord, je vois, je vais essayer ça. Merci beaucoup pour ton aide :)

                            Et tout comme toi, je n'ai plus de notif non plus...

                            • Partager sur Facebook
                            • Partager sur Twitter
                              20 novembre 2019 à 13:38:20

                              Pourrais-je solliciter une petite aide supplémentaire s'il te plait ? J'ai bien compris que je devais boucler pour vérifier si le champ 'url' est vide ou non, mais je ne vois pas comment le vérifier. A chaque fois que je cherche à récupérer les infos du champ, j'ai une erreur comme quoi 'url' n'est pas connu, ou que l'enfant n'existe pas (Child "url" does not exist.). Du coup je ne vois pas comment faire ma boucle.

                              Si tu peux m'éclairer s'il te plait, ou quelqu'un d'autre passant par là.

                              Merci :)

                              • Partager sur Facebook
                              • Partager sur Twitter
                                20 novembre 2019 à 14:39:08

                                Qu'as-tu essayé comme code ? Quel(s) message(s) d'erreur tu as reçu avec ?

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  21 novembre 2019 à 16:40:48

                                  Après de nombreux tests et un coup de main en interne, c'est désormais ok.

                                  Merci pour les conseils :)

                                  • Partager sur Facebook
                                  • Partager sur Twitter

                                  [Symfony 4] Upload de fichier

                                  × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                  × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                  • Editeur
                                  • Markdown