Formulaire de contact avec CakePHP
Voyons comment mettre en place cette fonctionnalité très courante sur un site : un simple formulaire de contact dans lequel nous demandons au visiteur son nom, son prénom, son adresse email et le message qu’il souhaite faire parvenir au webmaster, par email. Nous allons aborder deux aspects intéressants : l’utilisation d’un Modèle sans table, et le composant Email fourni par le framework.
1. Le Modèle Contact
Nous ne souhaitons pas ici enregistrer les emails qui seront envoyés, nous allons donc indiquer à Cake de ne pas utiliser de table ‘contacts’. Cela pose cependant un problème pour la structure d’un enregistrement : Cake ne sait plus sur quoi s’appuyer pour la définir ! Nous allons donc lui mâcher le travail en donnant le schéma de données au Modèle. Nous définirons ensuite quelques règles de validation qui devront être satisfaites avant que l’email ne soit effectivement envoyé.
<?php // {app}/models/contact.php class Contact extends AppModel { var $name = 'Contact'; // Nous n'utiliserons pas de table dans la base var $useTable = false; // Nous donnons donc à Cake la structure d'un enregistrement var $_schema = array( 'prenom' => array( 'type' => 'string', 'length' => 30 ), 'nom' => array( 'type' => 'string', 'length' => 30 ), 'email' => array( 'type' => 'string', 'length' => 50 ), 'message' => array( 'type' => 'text' ) ); // Règles de validation des données var $validate = array( 'nom' => array( 'rule' => 'notEmpty', 'required' => true, 'allowEmpty' => false, 'message' => "Votre nom doit être renseigné." ), 'prenom' => array( 'rule' => 'notEmpty', 'required' => true, 'allowEmpty' => false, 'message' => "Votre prénom doit être renseigné." ), 'email' => array( 'rule' => 'email', 'required' => true, 'allowEmpty' => false, 'message' => "Vous devez saisir une adresse email valide." ), 'message' => array( 'rule' => 'notEmpty', 'required' => true, 'allowEmpty' => false, 'message' => "Vous devez saisir un message." ) ); } ?>
2. Les vues
Nous aurons ici deux vues : la page qui affiche le formulaire lui-même, et une simple page de confirmation lorsque l’email est bien envoyé à l’administrateur du site.
2.1 La vue du formulaire
// {app}/views/contacts/index.ctp <h1>Formulaire de contact</h1> <?php e($form->create('Contact', array('url' => '/contacts/index'))); ?> <fieldset> <legend>Vos coordonnées</legend> <?php e($form->input('nom', array('label' => "Votre nom :", 'size' => 80))); e($form->input('prenom', array('label' => "Votre prénom :", 'size' => 80))); e($form->input('email', array('label' => "Votre adresse email :", 'size' => 80))); ?> </fieldset> <fieldset> <legend>Votre message</legend> <?php e($form->textarea('message', array('cols' => 60, 'rows' => 12))); ?> <?php e($form->error('message')); ?> </fieldset> <?php e($form->end("Envoyer le message")); ?>
Deux petits détails :
- nous forçons la cible du formulaire,
/contacts/index, sinon Cake la définit par défaut à/contacts/add - Nous forçons l’affichage de l’éventuelle erreur de validation sur le champ ‘message’, car la méthode
$form->textarea()ne va pas afficher l’erreur, contrairement à la méthode$form->input().
2.2 La vue de confirmation d’envoi
// {app}/contacts/confirmation.ctp <h1>Email envoyé</h1> <p>Merci de votre participation, etc.</p>
3. Le Contrôleur Contacts
C’est ici que nous allons inclure le Composant Email fourni par CakePHP. Notre Contrôleur ne va contenir que deux actions : index, qui affiche le formulaire et envoie un email à l’administrateur si le formulaire est soumis, et une action vide pour afficher la page de confirmation en cas de succès.
<?php class ContactsController extends AppController { var $name = 'Contacts'; var $components = array('Email'); function index() { if(!empty($this->data)) { $this->Contact->create($this->data); if(!$this->Contact->validates()) { $this->Session->setFlash("Veuillez corriger les erreurs mentionnées.", 'message_notice'); $this->validateErrors($this->Contact); } else { // Nettoyage de la saisie App::import('Sanitize'); $this->data = Sanitize::clean($this->data); $this->set('data', $this->data); $this->Email->charset = 'ISO-8859-1'; $this->Email->to = 'contact@monsite.com'; $this->Email->bcc = array($this->data['Contact']['email']); $this->Email->from = $this->data['Contact']['email']; $this->Email->sendAs = 'both'; $this->Email->subject = "Formulaire de contact"; $this->Email->template = 'contact'; // Envoi de l'email $this->Email->send(); $this->redirect(array('action' => 'confirmation')); } } } // Page de remerciement function confirmation() {} } ?>
Attardons-nous un peu sur l’envoi de l’email : il suffit de définir quelques paramètres pour l’email qui va être envoyé, et le Composant se charge du reste. Nous envoyons l’email à l’administrateur, avec une copie cachée pour l’expéditeur ($this->Email->bcc) qui pourra ainsi archiver sa demande. Notons que nous choisissons d’envoyer l’email en deux formats en même temps ($this->Email->sendAs = 'both') : HTML pour la mise en page, et texte brut pour une compatibilité maximum avec les clients de messagerie, qui sauront choisir le format à afficher.
4. Templates et layouts de l’email
Voyons maintenant comment mettre en page l’email lui-même. N’oublions pas que nous avons deux formats à gérer, HTML et texte brut.
4.1 Layouts
Commençons par examiner les layouts spéciaux réservés aux emails.
4.1.1 Layout HTML
// {app}/views/layouts/email/html/default.ctp <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html> <body> <p>Bonjour,</p> <?php e($content_for_layout);?> <p>A bientôt sur <a href="http://www.monsite.com">mon site</a> !</p> </body> </html>
4.1.2 Layout texte brut
// {app}/views/layouts/email/text/default.ctp Bonjour, <?php e($content_for_layout);?> A bientôt sur mon site ! http://www.monsite.com
4.2 Vues
Voyons enfin les vues du corps de l’email.
4.2.1 Vue HTML
// {app}/views/elements/email/html/contact.ctp <p>Merci de nous avoir contacté. Voici la copie de ce que va recevoir notre administrateur :</p> <p>Date : <?php e(date('d/m/Y H:i')); ?></p> <p>Envoyé par : <?php e($data['Contact']['nom'].' '.$data['Contact']['prenom']); ?></p> <p>Adresse email : <?php e($data['Contact']['email']); ?></p> <p>Message : <?php e($data['Contact']['message']); ?></p>
4.2.2 Vue texte brut
// {app}/views/elements/email/text/contact.ctp Merci de nous avoir contacté. Voici la copie de ce que va recevoir notre administrateur : Date : <?php e(date('d/m/Y H:i')); ?> Envoyé par : <?php e($data['Contact']['nom'].' '.$data['Contact']['prenom']); ?> Adresse email : <?php e($data['Contact']['email']); ?> Message : <?php e($data['Contact']['message']); ?>
Commentaires
26 août 2008 à 0:10
la force de la simplicité dans toute sa splendeur !
trop beau !
26 août 2008 à 0:33
Marrant ça, je venais justement de faire exactement la même chose il y a quelques jours.
J’ai du pas mal chercher pour comprendre comment fonctionnent les vues des mails, bonne initiative que de regrouper tout cela en un post.
La seule différence entre nos deux codes serait que tu utilises $this->Contact->create($this->data); là où j’utilise $this->Contact->set($this->data);
J’avoue que je ne connaissais pas Model::Create.
26 août 2008 à 8:41
J’utilise également cette méthode avec juste une variante : une vraie table en base de données pour sauvegarder les données du formulaire avant de l’envoyer. Cela permet :
- de récupérer les demandes de contact en cas de soucis avec les emails. Un export rapide de la table en format tableur envoyé au client et celui-ci n’a perdu aucun contact.
- d’envisager des évolutions sur la gestion des contacts, comme de marquer celles ayant été traitées etc
26 août 2008 à 9:03
J’allais dire la même chose que Matthieu. L’approche de Pierre-Emmanuel est cependant plus intéressante à titre pédagogique !
26 août 2008 à 9:40
Salut,
Très bon tuto encore une fois !
J’ai essayé de faire cela en suivant l’article du Cookbook sur la validation depuis un contrôleur, mais il n’y a pas l’astuce du $_schema car leur exemple utilise bien un modèle avec table !
Du coup j’avais du faire une méthode de validation dans mon contrôleur qui me “set” les messages d’erreurs pour le formulaire. Et donc je n’utilisais pas de modèle du tout (public $uses = array() dans le contrôleur)!
Mais le coup du $_schema est bien plus propre car il permet d’utiliser la “magie” Cake pour la validation d’un formulaire avec les retours d’erreurs.
Juste une petite remarque syntaxique cher Pierre-Emmanuel : dans les vues de confirmation, on ne dit pas “Merci pour nous avoir contacté”, mais “Merci DE “! ;o)
26 août 2008 à 10:06
[...] second détaille en profondeur la mise en place d’un formulaire de contact avec envoi de mail, ce qui [...]
26 août 2008 à 15:26
@Guillaume en effet, j’ai juste ajouté ça comme piste supplémentaire parce que ça m’est arrivé de perdre des emails de contact avant qu’on applique cette solution. Ça n’est cependant pas indispensable selon les besoins de chacun et l’astuce “model sans table” reste très utile.
26 août 2008 à 16:21
@avairet : merci, je corrige
27 août 2008 à 18:57
Encore excellent. J’adore tes tutoriels.
Celui-ci vient de m’éviter de chercher pendant des heures.
Merci!
28 janvier 2009 à 17:12
Bonjour et merci pour se super tutoriel.
mais voila j’ai un petit problème, lorsque je complète le formulaire avec des fautes (donc soit en oubliant le @ ou en n’encodant pas de nom) et que j’envoie, cakephp m’affiche en dégradé, sur tout la page, sa banniere “CakePHP: the rapid development php framework”
alors qu’il devrait m’indiquer le message d’erreur de l’email ou du nom défini dans les règle.
Je ne c’est plus quoi faire.
Merci d’avance pour vos réponses
ps: je suis débutant dans cakephp sa ne fait que 2 jours que je suis dessus
24 juin 2009 à 22:50
Il y a des problèmes apparament avec le champ bcc (idem avec cc). Les emails contenus dans le champ bcc ne sont pas pris en compte.
J’ai vu un ticket concernant une erreur lorsque les paramètres sont des scalaires (string simple) au lieu de tableaux (array) pour bcc et cc mais pas dans le fonctionnement de bcc.
Quelqu’un a t-il une idée de là ou ça peut provenir ? Fonction mail de l’hébergeur ou bien implémentation dans cake ? Quelqu’un a t’il teste avec le champ bcc ?
Merci davance !!