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']); ?>
Pierre-Emmanuel Fringant

Articles connexes

Commentaires

la force de la simplicité dans toute sa splendeur ! trop beau !

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.

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

J’allais dire la même chose que Matthieu. L’approche de Pierre-Emmanuel est cependant plus intéressante à titre pédagogique !

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)

[...] second détaille en profondeur la mise en place d’un formulaire de contact avec envoi de mail, ce qui [...]

@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.

@avairet : merci, je corrige ;)

Encore excellent. J’adore tes tutoriels.

Celui-ci vient de m’éviter de chercher pendant des heures.

Merci!

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

Bonjour, merci pour ce tuto qui sur d’autres sites fonctionne très bien… mais là j’ai ce curieux message lorsque j’envoie le mail :

Warning (2): Cannot modify header information - headers already sent by (output started at /srv/d_CSI/www/erwan.weborganic.mobi/htdocs/app/views/helpers/image.php:75) [CORE/cake/libs/controller/controller.php, line 615]
 
Code | Context
 
$status =   "Location: http://erwan.weborganic.mobi/contacts/confirmation"
 
header - [internal], line ??
Controller::header() - CORE/cake/libs/controller/controller.php, line 615
Controller::redirect() - CORE/cake/libs/controller/controller.php, line 596
ContactsController::index() - APP/controllers/contacts_controller.php, line 38
Object::dispatchMethod() - CORE/cake/libs/object.php, line 115
Dispatcher::_invoke() - CORE/cake/dispatcher.php, line 245
Dispatcher::dispatch() - CORE/cake/dispatcher.php, line 211
[main] - APP/webroot/index.php, line 88
 
(default) 0 query took ms Nr    Query   Error   Affected    Num. rows   Took (ms)

Si quelqu’un pouvait m’aider… ?

Cordialement

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 !!

Bonjour, à tous. Toujours utiles vos tutos. Une petite question, cependant:

// Nettoyage de la saisie App::import(‘Sanitize’); $this->data = Sanitize::clean($this->data);

est-ce vraiment indispensable? surtout quand on le couple à un contrôle sur la validation, du style (i18n oblige)

var $validate = NULL; function construct($id = false, $table = null, $ds = null) { parent::construct($id, $table, $ds); $this->validate = array(‘nom’ => array(‘r1_nom’ => array( ‘rule’ => ‘notEmpty’, ‘message’ => __(‘Required field’,true)),’r0_nom’ => array( ‘rule’ => array(‘maxLength’,’50′), ‘message’ => __(‘Maximum length of 50 characters’,true))), …. ); }

Car dans ce cas, il n’y a plus moyen d’envoyer un simple retour chariot dans le message…

Super tuto … sauf que petit problème si je rempli le formulaire en faisant des fautes (cad qui ne respecte pas les règles de validation) et que j’envoie, mon serveur localhost plante totalement (je travaille avec WAMP)

Si quelqu’un a une idée, merci d’avance

Merci pour ce bô tuto!

Cependant, je rencontre le même problème que Bob: Le site plante lorsqu’il subsiste des erreurs dans les différents champs au moment du clic sur « Envoyer le message ». –> Je suis alors obligé de supprimer le cookie généré pour voir à nouveau ma page.

Je remarque aussi un autre souci. Le texte du champ « message » n’apparait pas dans le corps du mail…

Je serais ravis si vous pouviez me donner l’une ou l’autre piste!

[...] comment réaliser de formualire de contact avec CakePHP, je vous invite à lire le tutoriel suivant http://www.formation-cakephp.com/71/formulaire-de-contact-avec-cakephp Il est vraiment bien expliqué et [...]

un message d’erreur : « Connexion réinitialisée »

Je pense que pour tester meme pour la fonction validate il nous faut un serveur mail donc pas sur un serveur local ;) . Sinon ne pensez vous pas que au niveau du controller : contacts_controller.php :

if(!$this->Contact->validates())
            {
                $this->Session->setFlash("Veuillez corriger les erreurs mentionnées.", 'message_notice');
                $this->validateErrors($this->Contact);
            }
il faut mettre :
if(!$this->Contact->validate())
            {
                $this->Session->setFlash("Veuillez corriger les erreurs mentionnées.", 'message_notice');
                $this->validateErrors($this->Contact);
            }
changer « validates » par « validate » ?!! Merci pour ce super Tuto

Génial ce tuto ! Par contre, j’ai une erreur dès que j’ajoute un template à l’aide de la méthode : $this->Email->template = ‘contact’;

Ca fonctionne sans, mais pas avec et j’ai bien les fichiers : app/views/elements/email/html/contact/ctp app/views/elements/email/text/contact/ctp

L’erreur est : Fatal error: Call to a member function addScript() on a non-object in /var/www/vhosts/NOMSITE.FR/httpdocs/cake/libs/view/helpers/javascript.php on line 277

Impossible de trouver quoi que ce soit sur internet. Je suis preneur de toute suggestion.

Merci

Bonjour, excellent tuto, mais je rencontre un problème avec sanitize et le caractère « - ». En effet j’aimerais l’autoriser, notamment pour les e-mails, mais je ne sais pas comment faire en utilisant clean()

Avez-vous une solution à cela ? Merci !

Bonjour, merci, ce tutoriel est excellent! J’ai un petit souci cependant, le message de confirmation s’affiche pour dire que le message a été envoyé, mais je ne trouve pas de mail dans ma boite. Avez vous une idée de l’origine de ce problème?

Merci d’avance!

@ nina : Si tu utilise wamp ou autre c’est normal que le mail ne soit pas envoyé… Tu doit le tester sur un serveur distant qui gérera l’envoie du mail.

Même si je travaille maintenant avec la version 2, j’ai quand même appris mal de chose, Un grand Merci

Participez

Pour insérer une portion de code, utilisez <pre lang="php">...</pre>