THELIA Forum

Welcome to the THELIA support and discusssion forum

Announcement

Rejoignez la communauté sur le Discord Thelia : https://discord.gg/YgwpYEE3y3

Offline


Bonjour,

J'ai ajouté un champ input de type file dans mon formulaire. Mon but est de transmettre le formulaire de contact avec une PJ laissée par l'utilisateur du formulaire.
Mon controleur ressemble à ça :

        try {
            $form = $this->validateForm($contactForm);
            
            $destinationPath = __DIR__.'/../../../../web/assets/';
            $file = move_uploaded_file($form->get('attach')->getData(),$destinationPath);
                        
            $message = \Swift_Message::newInstance($form->get('subject')->getData())
                ->addFrom(ConfigQuery::getStoreEmail(), $form->get('name')->getData())
                ->addReplyTo($form->get('email')->getData(), $form->get('name')->getData())
                ->addTo(ConfigQuery::getStoreEmail(), ConfigQuery::getStoreName())
                ->setBody($form->get('message')->getData())
                ->attach(\Swift_Attachment::fromPath($destinationPath,$form->get('attach')->getData()));

            $this->getMailer()->send($message);

Je suis redirigé vers la route contact/success mais je ne reçois rien, et pour cause : à aucun moment je n'ai uploadé le fichier sur le serveur !
Dans la doc Symfony, sur les différents forums, je ne vois jamais comment uploader le fichier. Je suis bloqué avec ça.

J'ai essayé aussi avec la methode move (je doute qu'on puisse l'utiliser pour uploader le fichier) maisla j'obtiens "Fatal error: Call to a member function move()"

Comment  récupérer le fichier de mon formulaire pour ensuite utiliser Swift_Attachment ?

Last edited by anti-conformiste (22-11-2017 16:44:50)

Offline


Ca ne peut pas marcher ton truc ! Si 'attach' a été ajouté au formulaire (pas seulement le formulaire HTML, mais aussi à l'objet Form associé), alors tu peux écrire quelque chose comme :

            /** @var \Symfony\Component\HttpFoundation\File\UploadedFile $uploadedFile */
            $uploadedFile = $form->get('attach')->getData();

            $destinationPath = THELIA_WEB_DIR . DS . 'assets' . DS . $uploadedFile->getClientOriginalName();

            /** @var Symfony\Component\HttpFoundation\File $localFile  */
             $localFile = $uploadedFile->move($destinationPath);

            $message = $this->getMailer()->createSimpleEmailMessage(
                [ ConfigQuery::getStoreEmail() => $form->get('name')->getData() ], // From
                [ $form->get('email')->getData() => $form->get('name')->getData() ], // To
                $form->get('subject')->getData(), // Sujet
                null, // HTML body
                $form->get('message')->getData() // text body
            );
            
            $message->attach(\Swift_Attachment::fromPath($localFile->getPathname());
            
            $this->getMailer()->send($message);

OpenStudio Toulouse

Offline


Merci Roadster.

Dans mon formulaire j'ai ça :

{form_field field="attach"}
       <div class="form-group col-md-12 col-sm-12 col-xs-12">
           <div class="field-label">Objet : *</div>
               <input type="file" name="{$name}" id="attach" placeholder="" required>
           </div>
{/form_field}

Est-ce ce que tu entends par 'l'objet Form associé' ?

J'ai intégré ton code. J'ai cette erreur :

Fatal error: Call to a member function getClientOriginalName() on string

Last edited by anti-conformiste (19-11-2017 21:18:52)

Offline


Est-ce ce que tu entends par 'l'objet Form associé' ?

La classe qui définir la Form, par exemple core/lib/Thelia/Form/ContactForm


OpenStudio Toulouse

Offline


Dans local/modules/Formulaire/Form/ContactForm.php, j'ai :

<?php
/*************************************************************************************/
/*      This file is part of the Thelia package.                                     */
/*                                                                                   */
/*      Copyright (c) OpenStudio                                                     */
/*      email : dev@thelia.net                                                       */
/*      web : http://www.thelia.net                                                  */
/*                                                                                   */
/*      For the full copyright and license information, please view the LICENSE.txt  */
/*      file that was distributed with this source code.                             */
/*************************************************************************************/

namespace Formulaire\Form;

use Formulaire\Formulaire;
use Symfony\Component\Validator\Constraints\Email;
use Symfony\Component\Validator\Constraints\NotBlank;
use Thelia\Core\Translation\Translator;
use Thelia\Form\FirewallForm;

/**
 * Class ContactForm
 * @package Thelia\Form
 * @author Manuel Raynaud <manu@thelia.net>
 */
class ContactForm extends FirewallForm
{
    protected function buildForm()
    {
        $this->formBuilder
            ->add('name', 'text', array(
                'constraints' => array(
                    new NotBlank()
                ),
                'label' => $this->translator->trans('name', [], Formulaire::DOMAIN_NAME),
                'label_attr' => [
                    'placeholder' => $this->translator->trans('Your Name', [], Formulaire::DOMAIN_NAME),
                ]
            ))
            ->add('email', 'email', array(
                'constraints' => array(
                    new NotBlank()
                ),
                'label' => $this->translator->trans('Email address', [], Formulaire::DOMAIN_NAME),
                'label_attr' => [
                    'placeholder' => $this->translator->trans('Your e-mail address', [], Formulaire::DOMAIN_NAME),
                ]
            ))
            ->add('subject', 'text', array(
                'constraints' => array(
                    new NotBlank()
                ),
                'label' => $this->translator->trans('Subject', [], Formulaire::DOMAIN_NAME),
                'label_attr' => [
                    'placeholder' => $this->translator->trans('Subject', [], Formulaire::DOMAIN_NAME),
                ]
            ))
            ->add('attach', 'file', array(
                'constraints' => array(
                    new NotBlank()
                ),
                'label' => $this->translator->trans('Attach', [], Formulaire::DOMAIN_NAME),
                'label_attr' => [
                    'placeholder' => $this->translator->trans('Document joint', [], Formulaire::DOMAIN_NAME),
                ]
            ))
            ->add('message', 'textarea', array(
                'constraints' => array(
                    new NotBlank()
                ),
                'label' => $this->translator->trans('Your Message', [], Formulaire::DOMAIN_NAME),
                'label_attr' => [
                    'placeholder' => $this->translator->trans('Please enter your message here.', [], Formulaire::DOMAIN_NAME),
                ]
            ))
        ;
    }

    /**
     * @return string the name of you form. This name must be unique
     */
    public function getName()
    {
        return 'formulaire_form';
    }
}

Last edited by anti-conformiste (19-11-2017 21:37:31)

Offline


Je sais, c'est un fichier du Core

C'est quoi l'ID de la form que tu modifie, le name dans {form name="???" ...}


OpenStudio Toulouse

Offline


Je sais que tu sais et que tout cela doit te paraître au raz des paquerettes, sans minimiser nos efforts de débutants ;-)

Je n'ai en effet pas précisé que j'ai généré les bases d'un module en ligne de commande grâce à la doc. Je l'ai appelé formulaire.custom. Il se trouve dans un dossier nommé 'Formulaire' dans local/modules
C'est exactement le même que le formulaire de contact du 'Front' avec les champs personnalisés que j'ajoute ou retire de ce module sur chacun de mes sites, en fonction de mes besoins. Jusqu'à présent, des champs 'simples' ne nécessitainent pas réellement d'ajout de code. La lecture de la doc, l'analyse de la structure d'un module 'de base' comme celui-ci, quelques efforts intellectuels et du temps me permettent d'arriver à mes fin.

Cependant, avec un champ 'file', j'ai compris que l'histoire se corsait un peut et qu'il me fallait comprendre la POO à minima, les classes, les objets et les methodes. J'assure que je fais tous ces efforts, mais je suis rattrapé par le temps et ma volonté ne suffit pas toujours sans reprendre quelques bases de programmation.

En réponse à ta question :

{block name="contact-form"}
                    	{form name="formulaire.custom"}
                    	<form id="form-contact" action='{url route_id="contact.send"}' method="post">
                    	{form_hidden_fields}
                            <div class="row clearfix">
                                {form_field field="name"}
                                <div class="form-group col-md-6 col-sm-12 col-xs-12">
                                	<div class="field-label">Nom *</div>
                                	<input type="text" name="{$name}" id="name" placeholder="" required>
                                </div>
                                {/form_field}
                                {form_field field="email"}
                                <div class="form-group col-md-6 col-sm-12 col-xs-12">
                                	<div class="field-label">Votre E-mail *</div>
                                	<input type="email" name="{$name}" id="email" placeholder="" required>
                                </div>
                                {/form_field}
                                {form_field field="subject"}
                                <div class="form-group col-md-12 col-sm-12 col-xs-12">
                                	<div class="field-label">Objet : *</div>
                                	<input type="text" name="{$name}" id="subject" placeholder="" required>
                                </div>
                                {/form_field}
                                {form_field field="attach"}
                                <div class="form-group col-md-12 col-sm-12 col-xs-12">
                                	<div class="field-label">Objet : *</div>
                                	<input type="file" name="{$name}" id="attach" placeholder="" required>
                                </div>
                                {/form_field}
                                {form_field field="message"}
                                <div class="form-group col-md-12 col-sm-12 col-xs-12">
                                    <div class="field-label">Message *</div>
                                    <textarea name="{$name}" id="message" placeholder="" required></textarea>
                                </div>
                                {/form_field}
                                <div class="form-group col-md-12 col-sm-12 col-xs-12 text-right">
                                    <button class="normal-btn theme-btn" type="submit" name="submit-form">ENVOYER</button>
                                </div>
                            </div>
                        </form>
                        {/form}
                    {/block}

J'ai essayé d'appréhender 'Doctrine', j'ai cru comprendre à travers mes diverses lectures sur le sujet qu'il fallait créer une entité "fichier", en définir le type et appeler dans mon controleur cet objet avant de le traiter dans la partie code de mon formulaire : https://symfony.com/doc/2.6/cookbook/co … _file.html

Mais mon intuition me dit qu'il y a un chemin plus simple et que je ne suis pas forcémment obligé de définir le type de fichier (jpeg, png, pdf, etc...) : en effet, je souhaite que l'utilisateur puisse transmettre n'importe quel type de fichier. Mais peut-être cela pose-t-il des problèmes de sécurité, ce que je peux comprendre...

Bref, je fais des efforts, mais chaque question en amène une autre :-)

Offline


Pas besoin de POO de barbu, ou de Doctrine (que Thelia 2 n'utilises pas, d'ailleurs, puisque l'ORM choisi est Propel).

Il semble que ton champ 'attach' aie été déclaré correctement, et donc $form->get('attach')->getData() doit te retourner une instance de \Symfony\Component\HttpFoundation\File\UploadedFile, que tu peux manipuler comme je te l'ai indiqué.


OpenStudio Toulouse

Offline


J'ai vérifié et re-vérifié avec ton code. J'ai juste ajouté une 'tite paenthèse (passée à la trappe) à la fin de cette ligne :

$message->attach(\Swift_Attachment::fromPath($localFile->getPathname());

Mais j'ai toujours

FatalThrowableError in ContactController.php line 53:
Fatal error: Call to a member function getClientOriginalName() on string

Le problème viendrait pas de cette partie de la classe qui définit la Form :

->add('attach', 'file', array(
                'constraints' => array(
                    new NotBlank()
                ),
                'label' => $this->translator->trans('Attach', [], Formulaire::DOMAIN_NAME),
                'label_attr' => [
                    'placeholder' => $this->translator->trans('Document joint', [], Formulaire::DOMAIN_NAME),
                ]
            ))

D'habitude c'est un

->add('nom_du_champ', 'text'...

que j'ai remplacé par un

->add('attach', 'file' dans ma logique.

Last edited by anti-conformiste (20-11-2017 14:14:55)

Offline


Il faut débugger.

Y'a quoi dans $uploadedFile ?


OpenStudio Toulouse

Offline


J'ai installé la DebugBar, mais il semble qu'elle ne fonctionne plus avec les dernières versions de thelia.
J'ai voulu installer Firephp, mais il n'est pas compatible avec FF Quantum.
J'ai essayé cette suggestion, mais sans succès.

Une suggestion ? Faut quand même pas installer Xdebug avec un IDE ?
Comment envoyer une variable dans la console de firefox (ou autre) ou tout simplement faire un "echo alert($variable);" ?

Offline


Faut quand même pas installer Xdebug avec un IDE ?

C'est tellement confortable, quel dommage de s'en priver. Pour débugger, mais aussi naviguer dans le code, avoir l'auto complétion, et mille autres outils tellement pratiques. Coder sans débuggeur, c'est comme se déplacer dans Paris avec les yeux et les oreilles bouchés !

Sinon, tu peux faire des echo et des print_r() dans le code PHP (en mode développement).


OpenStudio Toulouse

Offline


J'ai activé l'extension PHP xdebug chez o2switch

J'ai installé eclipse. Il me faut juste ouvrir la page PHP du controlleur et y mettre un point d'arrêt ?

Où je suis à côté de la plaque et il faut copier le site distant en local, créer un projet avec mon module, l'exécuter en local, installer l'extention xdebug sur FF pour enfin récupérer juste le contenu de ma variable ?

Offline


Tu peux aussi faire un print_r...


OpenStudio Toulouse

Offline


print_r($uploadedFile); renvoie le nom de ma pièce jointe...

Je remets le code complet du controleur en dessous pour faciliter les choses :

Last edited by anti-conformiste (21-11-2017 13:21:42)

Offline


<?php
/*************************************************************************************/
/*                                                                                   */
/*      Thelia                                                                         */
/*                                                                                   */
/*      Copyright (c) OpenStudio                                                     */
/*      email : info@thelia.net                                                      */
/*      web : http://www.thelia.net                                                  */
/*                                                                                   */
/*      This program is free software; you can redistribute it and/or modify         */
/*      it under the terms of the GNU General Public License as published by         */
/*      the Free Software Foundation; either version 3 of the License                */
/*                                                                                   */
/*      This program is distributed in the hope that it will be useful,              */
/*      but WITHOUT ANY WARRANTY; without even the implied warranty of               */
/*      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                */
/*      GNU General Public License for more details.                                 */
/*                                                                                   */
/*      You should have received a copy of the GNU General Public License            */
/*        along with this program. If not, see <http://www.gnu.org/licenses/>.         */
/*                                                                                   */
/*************************************************************************************/

namespace Formulaire\Controller;

use Formulaire\Formulaire;
use Thelia\Controller\Front\BaseFrontController;
use Thelia\Form\Exception\FormValidationException;
use Thelia\Log\Tlog;
use Thelia\Model\ConfigQuery;

/**
* Class ContactController
* @package Thelia\Controller\Front
* @author Manuel Raynaud <manu@raynaud.io>
*/

class ContactController extends BaseFrontController
{
    /**
     * send contact message
     */
    public function sendAction()
    {
        $contactForm = $this->createForm(Formulaire::FORM_NAME);

        try {
            $form = $this->validateForm($contactForm);
           
               
            /** @var \Symfony\Component\HttpFoundation\File\UploadedFile $uploadedFile */
            $uploadedFile = $form->get('attach')->getData();
           
            print_r($uploadedFile);
                       
            $destinationPath = THELIA_WEB_DIR . DS . 'assets' . DS . $uploadedFile->getClientOriginalName();

            /** @var Symfony\Component\HttpFoundation\File $localFile  */
            $localFile = $uploadedFile->move($destinationPath);

            $message = $this->getMailer()->createSimpleEmailMessage(
                [ ConfigQuery::getStoreEmail() => $form->get('name')->getData() ], // From
                [ $form->get('email')->getData() => $form->get('name')->getData() ], // To
                $form->get('subject')->getData(), // Sujet
                null, // HTML body
                $form->get('message')->getData() // text body
            );
           
            $message->attach(\Swift_Attachment::fromPath($localFile->getPathname()));
           
            $this->getMailer()->send($message);

            if ($contactForm->hasSuccessUrl()) {
                return $this->generateSuccessRedirect($contactForm);
            }

            return $this->generateRedirectFromRoute('contact.success');

        } catch (FormValidationException $e) {
            $error_message = $e->getMessage();
        }

        Tlog::getInstance()->error(sprintf('Error during sending contact mail : %s', $error_message));

        $contactForm->setErrorMessage($error_message);

        $this->getParserContext()
            ->addForm($contactForm)
            ->setGeneralError($error_message)
        ;

        // Redirect to error URL if defined
        if ($contactForm->hasErrorUrl()) {
            return $this->generateErrorRedirect($contactForm);
        }
    }
}

Offline


la console de Firefox dit

Form contains a file input, but is missing method=POST and enctype=multipart/form-data on the form.  The file will not be sent.

index_dev.php/contact dit

Whoops, looks like something went wrong.

1/1
FatalThrowableError in ContactController.php line 57:
Fatal error: Call to a member function getClientOriginalName() on string
in ContactController.php line 57
at ContactController->sendAction()
at call_user_func_array(array(object(ContactController), 'sendAction'), array()) in HttpKernel.php line 139
at HttpKernel->handleRaw(object(Request), '1') in HttpKernel.php line 62
at HttpKernel->handle(object(Request), '1', true) in TheliaHttpKernel.php line 76
at TheliaHttpKernel->handle(object(Request), '1', true) in ParamInitMiddleware.php line 87
at ParamInitMiddleware->handle(object(Request), '1', true) in SessionMiddleware.php line 80
at SessionMiddleware->handle(object(Request), '1', true) in StackedHttpKernel.php line 23
at StackedHttpKernel->handle(object(Request), '1', true) in Kernel.php line 185
at Kernel->handle(object(Request)) in index_dev.php line 37

La ligne 57 :

$destinationPath = THELIA_WEB_DIR . DS . 'assets' . DS . $uploadedFile->getClientOriginalName();

Offline


Si j'ajoute enctype="multipart/form-data" à ma balise ouvrante form, print_r($uploadedFile) dit

Symfony\Component\HttpFoundation\File\UploadedFile Object ( [test:Symfony\Component\HttpFoundation\File\UploadedFile:private] => [originalName:Symfony\Component\HttpFoundation\File\UploadedFile:private] => document.pdf [mimeType:Symfony\Component\HttpFoundation\File\UploadedFile:private] => application/pdf [size:Symfony\Component\HttpFoundation\File\UploadedFile:private] => 48460 [error:Symfony\Component\HttpFoundation\File\UploadedFile:private] => 0 [pathName:SplFileInfo:private] => /tmp/phpPChsDS [fileName:SplFileInfo:private] => phpPChsDS )

et index_dev.php/contact dit

Whoops, looks like something went wrong.

1/1
FatalThrowableError in ContactController.php line 62:
Fatal error: Call to undefined method Thelia\Mailer\MailerFactory::createSimpleEmailMessage()
in ContactController.php line 62
at ContactController->sendAction()
at call_user_func_array(array(object(ContactController), 'sendAction'), array()) in HttpKernel.php line 139
at HttpKernel->handleRaw(object(Request), '1') in HttpKernel.php line 62
at HttpKernel->handle(object(Request), '1', true) in TheliaHttpKernel.php line 76
at TheliaHttpKernel->handle(object(Request), '1', true) in ParamInitMiddleware.php line 87
at ParamInitMiddleware->handle(object(Request), '1', true) in SessionMiddleware.php line 80
at SessionMiddleware->handle(object(Request), '1', true) in StackedHttpKernel.php line 23
at StackedHttpKernel->handle(object(Request), '1', true) in Kernel.php line 185
at Kernel->handle(object(Request)) in index_dev.php line 37

Offline


Si j'ajoute enctype="multipart/form-data" à ma balise ouvrante form

Ha oui... C'est indispensable pour uploader un fichier. Tu aurais pu utiliser {form_enctype form=$form}, qui décide automatiquement de l'ajouter ou pas en fonction des champs définis dans la form (cf. http://doc.thelia.net/en/documentation/ … isplay-it).

La méthode createSimpleEmailMessage() existe dans la classe MailerFactory dans Thelia 2.3.4 et même avant), cf https://github.com/thelia/thelia/blob/2 … y.php#L275. Quelle version de Thelia utilises tu ?


OpenStudio Toulouse

Offline


php Thelia -V    
#!/usr/bin/env php
Thelia version 2.3.3

Last edited by anti-conformiste (21-11-2017 17:13:07)

Offline


Oups, je me suis trompé, cette méthode est dispo à partir de la 2.3.4


OpenStudio Toulouse

Offline


Ne sois pas si modeste ;-)

nonobstant la version,  le problème persiste.

Pour info, j'ai regénéré un module en ligne de commande, j'ai mmodifié l'objet form avec mes champs, j'ai réintégré ton code dans mon module formulaire et le problème est le même.

J'essaie de le résoudre seul, avec témérité, pugnacité, perseverence. Merci aussi pour ces informations et ce temps que tu m'accordes. C'est pas de la pommade. Je connais le prix de la prestation et du bénévolat.

Bref, ces bons mots ne changent rien au fait que je suis un boulet sur ce coup là.

Concrétement, j'ai l'impression que la variable récupère le nom du fichier joint et non un array avec la PJ. C'est juste une intuition.

Offline


Tu récupères un objet UploadedFile, et c'est parfaitement normal.

Le problème qui reste, c'est juste que tu ne peux pas utiliser la méthode createSimpleEmailMessage de MailerFactory, parce qu'elle n'existe pas encore en 2.3.3. C'est le sens du message d'erreur "Call to undefined method Thelia\Mailer\MailerFactory::createSimpleEmailMessage()"


OpenStudio Toulouse

Offline


Ok, je fais la MAJ vers la 2.3.4

Mais comment on faisait avant alors ?

Offline


Comment on faisait pour envoyer un mail avant que la méthode Thelia\Mailer\MailerFactory::createSimpleEmailMessage() n'existe ? Ben comme toi dans le 1er post, on utilisait directement la classe Swift_Message. Tu peux toujours le faire, d'ailleurs.

$message = \Swift_Message::newInstance($form->get('subject')->getData())
    ->addFrom(ConfigQuery::getStoreEmail(), $form->get('name')->getData())
    ->addReplyTo($form->get('email')->getData(), $form->get('name')->getData())
    ->addTo(ConfigQuery::getStoreEmail(), ConfigQuery::getStoreName())
    ->setBody($form->get('message')->getData())
    ->attach(\Swift_Attachment::fromPath($localFile->getPathname());

     $this->getMailer()->send($message);

OpenStudio Toulouse