IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Symfony PHP Discussion :

Envoi d'un fichier via un formulaire


Sujet :

Symfony PHP

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    209
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 209
    Par défaut Envoi d'un fichier via un formulaire
    Bonjour !

    J'essaye de faire un système d'upload de fichier, insertion en bdd puis lecture de celui-ci !

    Pour le moment j'arrive à procéder à l’envoi d'un fichier spécifique déjà stocké en dur dans un répertoire du site via une commande ! Maintenant l’étape suivante que j'aimerais réaliser et que le fichier soit choisis par l'utilisateur !
    Du coup, j'ai consulté la doc de SF sur les envois de fichier : https://symfony.com/doc/current/cont...load_file.html et décider de m'en inspirer !

    Voici mon controller :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
     
        #[Route('/signalement/upload', name: 'signalement.upload', methods:['GET', 'POST'])]
        public function upload(
            Request $request,
            SluggerInterface $slugger,
             #[Autowire('%kernel.project_dir%/public/uploads/')] string $fileDirectory
        )  : Response {
                $upload = new Upload();
                $form = $this->createForm(ImportType::class, $upload);
                $form->handleRequest($request);
                if ($form->isSubmitted() && $form->isValid()) {
                    $file = $form -> get('csvFile')->getData();
                    if($file){
                        $fileName = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
                        $safeFileName = $slugger->slug($fileName);
                        $newFileName = $safeFileName.'-'.uniqid().'.'.$file->guessExtension();
                        $upload->setCsvFile($newFileName);
                        $csv = Reader::createFromPath('%kernel.root.dir%/../public/uploads/'.$fileName);
                        $csv->setHeaderOffset(0);
                        $csv->setDelimiter(';');
                        $csv->setEscape('');
                        $records = $csv->getRecords();
                        foreach ($records as $record){ 
                            $signalement = (new Signalement())
                                ->setNumero($record['Identifiant de la fiche'])
                                //etc..
                                ;
                                $this->em->persist($signalement);
                        }                    
                    }
                    $this->em->flush();
                        $this->addFlash('success','Bien ajouté avec succès');
                        return $this->redirectToRoute('signalement.index');
                }
            return $this->render('pages/signalement/upload.html.twig',
                ['form' => $form,]);
        }
    Première erreur que j'ai, qui est lié à la ligne de l'autowire ! J'avoue avoir un peu copié bêtement le code de la doc avec cette ligne et l'avoir mis à ma sauce... J'ai consulté la doc sur l'Autowire et j'avoue ne pas trop comprendre... P'tet un peu dur vu mon niveau
    Voici l'erreur que je rencontre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    Controller "App\Controller\SignalementController::upload" requires the "$fileDirectory" argument that could not be resolved. Either the argument is nullable and no null value has been provided, no default value has been provided or there is a non-optional argument after this one.
    Dans la doc , je n'ai pas trouvé le lien avec cette variable si elle était définie ailleurs etc etc...(à part plus bas dans le try{} mais j'ai essayé aussi avec cette option mais ca ne change rien). Je me demande aussi si l'url était bonne et si je devais avoir un dossier "uploads" dans mon dossier "public"

    J'ai bien évidement tenté sans l'Autowire mais la j'ai une autre erreur qui apparait lors de l'envoi du fichier :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    `%kernel.root.dir%/../public/uploads/test`: failed to open stream: No such file or directory.
    Bref j'avoue être un peu perdu entre la doc de SF mes tentatives et mes autres recherche sur internet ! Bref je sèche ! Merci

  2. #2
    Membre émérite
    Homme Profil pro
    Autre
    Inscrit en
    Juillet 2021
    Messages
    481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Autre

    Informations forums :
    Inscription : Juillet 2021
    Messages : 481
    Par défaut
    Bonjour,

    Pour la première erreur, as tu bien pensé à ajouter le use Autowire au début de ton contrôleur ?
    use Symfony\Component\DependencyInjection\Attribute\Autowire;

    La deuxième erreur indique que le chemin est incorrect car tu ne récupères pas correctement la valeur du paramètre dans Reader::createFromPath('%kernel.root.dir%/../public/uploads/'.$fileName)
    Tu peux utiliser la méthode getParameter() de ton contrôleur pour récupérer la valeur du paramètre de configuration :
    https://symfony.com/doc/current/cont...uration-values

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    209
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 209
    Par défaut
    Pour le premier souci, je l'avais bien importer mais je l'avais commenter pfff

    Par contre j'ai effectivement toujours ce souci de récupération de paramètres !
    J'ai bien regardé ton lien mais j'ai peur de ne pas savoir comment le mettre en place dans mon code :/
    De ce que je comprends le getParameter() sert a utiliser les paramètres de configurations défini dans le service.yaml ? https://symfony.com/doc/current/conf...ion-parameters
    Ou alors j'ai (encore) pas compris la doc mais chez moi je n'ai aucun paramètre et je ne sais pas trop quoi mettre dedans si je dois mettre quelques chose...
    Finalement la ligne
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     $csv = Reader::createFromPath('%kernel.root.dir%/../public/uploads/alertes/'.$fileName);
    doit être remplacer par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $csv = getParameter('parametre').$fileName
    ?

  4. #4
    Membre émérite
    Homme Profil pro
    Autre
    Inscrit en
    Juillet 2021
    Messages
    481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Autre

    Informations forums :
    Inscription : Juillet 2021
    Messages : 481
    Par défaut
    La méthode getParameter() du contrôleur permet de récupérer tes propres paramètres définis dans services.yaml mais aussi les paramètres du framework et des bundles (essaye la commande php bin/console debug:config pour voir les paramètres de ton projet).

    Le paramètre kernel.project_dir est défini par la classe Kernel de Symfony.

    La correction devrait ressembler à ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $csv = Reader::createFromPath($this->getParameter('kernel.project_dir') . '/public/uploads/alertes/' . $fileName);

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    209
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 209
    Par défaut
    Citation Envoyé par Pytet Voir le message
    La méthode getParameter() du contrôleur permet de récupérer tes propres paramètres définis dans services.yaml mais aussi les paramètres du framework et des bundles (essaye la commande php bin/console debug:config pour voir les paramètres de ton projet).
    Alors moi il m'affiche effectivement une liste "Bundle name" et "Extension alias" avec notament doctrine turbo twig etc mais je ne vois pas vraiment de paramètres

    Le paramètre kernel.project_dir est défini par la classe Kernel de Symfony.

    La correction devrait ressembler à ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $csv = Reader::createFromPath($this->getParameter('kernel.project_dir') . '/public/uploads/alertes/' . $fileName);
    Hummmm ok ! J'avais pas compris que le paramètre était "natif" (je le lisais comme un "exemple" dans la doc)

    Ceci dit j'ai toujours
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    failed to open stream: No such file or directory.
    Alors j'ai regarder mon service.yaml :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
     
    parameters:
     
     
    services:
        # default configuration for services in *this* file
        _defaults:
            autowire: true      # Automatically injects dependencies in your services.
            autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
     
        # makes classes in src/ available to be used as services
        # this creates a service per class whose id is the fully-qualified class name
        App\:
            resource: '../src/'
            exclude:
                - '../src/DependencyInjection/'
                - '../src/Entity/'
                - '../src/Kernel.php'
     
        App\EntityListener\:
            resource: "../src/EntityListener/"
            tags: ["doctrine.orm.entity_listener"]
    Il ne me manque pas quelques chose à tout hasard ?

  6. #6
    Membre émérite
    Homme Profil pro
    Autre
    Inscrit en
    Juillet 2021
    Messages
    481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Autre

    Informations forums :
    Inscription : Juillet 2021
    Messages : 481
    Par défaut
    Cette erreur n'est pas liée à ton service.yaml, l'erreur indique simplement que le fichier n'existe pas.

    Tu essayes d'accéder au fichier uploadé via $fileName qui contient le nom d'origine du fichier ($fileName = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);), or le fichier uploadé possède un nom temporaire différent du nom d'origine du fichier.

    Tu peux t'inspirer de l'exemple du contrôleur de la doc pour définir un nouveau nom unique au fichier uploadé ($newFileName dans l'exemple) et utiliser la méthode move() de ton instance UploadFile (la variable $file dans ton code).
    Tu pourras ensuite utiliser ce nouveau fichier renommé et déplacé pour le traitement du csv.

    Dans l'idée (code non testé) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    #[Route('/signalement/upload', name: 'signalement.upload', methods:['GET', 'POST'])]
    public function upload(
        Request $request,
        SluggerInterface $slugger,
        #[Autowire('%kernel.project_dir%/public/uploads/')] string $fileDirectory
    ): Response
    {
        $upload = new Upload();
     
        $form = $this->createForm(ImportType::class, $upload);
        $form->handleRequest($request);
     
        if ($form->isSubmitted() && $form->isValid()) {
        	/** @var UploadedFile $csvFile */
            $csvFile = $form->get('csvFile')->getData();
     
            if ($csvFile) {
                $originalFilename = pathinfo($csvFile->getClientOriginalName(), PATHINFO_FILENAME);
                $safeFilename = $slugger->slug($originalFilename);
                $newFilename = $safeFilename.'-'.uniqid().'.'.$csvFile->guessExtension();
     
                $csvFile->move($fileDirectory, $newFilename);
     
                $upload->setCsvFile($newFilename);
                $this->em->persist($upload);
     
                $csv = Reader::createFromPath($fileDirectory.$newFilename);
                // ...
            }
     
            $this->em->flush();
     
            $this->addFlash('success','Bien ajouté avec succès');
            return $this->redirectToRoute('signalement.index');
        }
     
        return $this->render('pages/signalement/upload.html.twig', ['form' => $form,]);
    }

  7. #7
    Membre confirmé
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    209
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 209
    Par défaut
    hummmm effectivement j'avais mis le move() avant comme dans le lien avec le try/catch mais vu que je l'utilisais mal apparemment, je l'avais mis en commentaire... Du coup j'ai voulu un peu me documenter sur cette methode et bizarrement j'ai rien trouvé que ce soit sur la doc de SF ou de PHP :/ Mais si je comprend bien , cette méthode interverti les 2 arguments en paramètre ? ici le nom d'origine du csv ($fileDirectory) et le nom avec l'id unique ($newFileName) ?

    Par contre, en laissant mes em ca me met des messages d'erreur Warning: Undefined property: App\Controller\SignalementController::$em ce qui me semble logique... (du coup j'ai remplacer chaque $this->em-> en
    $manager-> et ca passe bien !!

    En tout cas encore une fois merci pour ton aide mais il va falloir que je décrypte très sérieusement chaque étape de ce code car ça reste flou et j'aime pas trop ça !!

  8. #8
    Membre émérite
    Homme Profil pro
    Autre
    Inscrit en
    Juillet 2021
    Messages
    481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Autre

    Informations forums :
    Inscription : Juillet 2021
    Messages : 481
    Par défaut
    Lors de l'upload d'un fichier en PHP sans Symfony, le fichier uploadé est stocké temporairement dans le dossier temporaire du système, son nom temporaire est accessible dans la superglobale $_FILES['userfile']['tmp_name'] et le nom d'origine du fichier est dans $_FILES['userfile']['name'].
    Le fichier temporaire sera automatiquement effacé du dossier temporaire à la fin du script, s'il n'a pas été déplacé ou renommé.
    PHP propose alors la fonction move_uploaded_file() pour déplacer le fichier temporaire (et le renommer en même temps si besoin).
    https://www.php.net/manual/fr/featur...ost-method.php

    Symfony encapsule ce comportement dans les classes du framework, notamment la classe UploadedFile.
    Lors de l'upload via Symfony, le fichier uploadé est également stocké dans un dossier temporaire, son nom temporaire est accessible via la méthode UploadedFile::getName() (méthode héritée de la classe File) et le nom d'origine du fichier est dans UploadedFile::getClientOriginalName().
    La classe UploadedFile propose la méthode move() pour déplacer/renommer le fichier temporaire, tu peux voir dans le code source de cette méthode qu'elle utilise la fonction PHP move_uploaded_file().
    La méthode move() requiert 2 paramètres : $directory qui correspond au dossier ou sera déplacé le fichier uploadé et $name qui correspond au nouveau nom du fichier (qui peut être le nom d'origine du fichier si on veut mais on préfère en général le renommer pour ne pas écraser un fichier uploadé avec le même nom).

  9. #9
    Membre confirmé
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    209
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 209
    Par défaut
    Merci beaucoup pour tes explications je comprend un peu mieux la méthode et pourquoi je trouvais move_uploaded_file()lors de mes recherches et pas move()

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 3
    Dernier message: 28/04/2009, 21h30
  2. Réponses: 4
    Dernier message: 22/02/2008, 13h43
  3. Réponses: 5
    Dernier message: 03/04/2007, 17h11
  4. transférer un fichier via un formulaire
    Par dams78 dans le forum Langage
    Réponses: 8
    Dernier message: 03/04/2006, 21h15
  5. envoie de fichiers via les formulaires
    Par fabogranqi dans le forum Balisage (X)HTML et validation W3C
    Réponses: 6
    Dernier message: 10/10/2004, 22h34

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo