Créons un formulaire de contact
Voyons comment créer dans Nette un formulaire de contact, envoi des données saisies par e-mail compris. Allons-y !
Nous devons d'abord créer un nouveau projet. La page Premiers pas explique comment faire. Nous pouvons ensuite commencer à créer le formulaire.
L'approche la plus simple est de créer le formulaire directement dans le
presenter. Nous pouvons utiliser le HomePresenter déjà existant. Nous y ajouterons un composant nommé
contactForm qui représentera notre formulaire. Pour cela, nous ajoutons au code du presenter une méthode fabrique
createComponentContactForm(), qui créera le composant :
use Nette\Application\UI\Form;
use Nette\Application\UI\Presenter;
class HomePresenter extends Presenter
{
protected function createComponentContactForm(): Form
{
$form = new Form;
$form->addText('name', 'Nom :')
->setRequired('Veuillez saisir votre nom');
$form->addEmail('email', 'E-mail :')
->setRequired('Veuillez saisir votre e-mail');
$form->addTextArea('message', 'Message :')
->setRequired('Veuillez saisir un message');
$form->addSubmit('send', 'Envoyer');
$form->onSuccess[] = $this->contactFormSucceeded(...);
return $form;
}
private function contactFormSucceeded(Form $form, $data): void
{
// envoi d'un e-mail
}
}
Comme vous le voyez, nous avons créé deux méthodes. La première, createComponentContactForm(), crée une
nouvelle instance du formulaire. Elle contient les champs pour le nom, l'e-mail et le message, ajoutés respectivement par les
méthodes addText(), addEmail() et addTextArea(). Nous avons aussi ajouté un bouton
d'envoi. Mais que se passe-t-il si l'utilisateur laisse un champ vide ? Dans ce cas, nous devrions lui signaler que le champ est
obligatoire. Nous y sommes parvenus à l'aide de la méthode setRequired(). Enfin, nous avons accroché un
gestionnaire d'événement à onSuccess, qui est
déclenché après l'envoi réussi du formulaire. Dans notre cas, il appelle la méthode contactFormSucceeded, qui se
chargera du traitement des données soumises. Nous l'implémenterons dans un instant.
Rendons le composant contactForm dans le template Home/default.latte :
{block content}
<h1>Formulaire de contact</h1>
{control contactForm}
Pour l'envoi de l'e-mail lui-même, nous créerons une nouvelle classe nommée ContactFacade et la placerons dans
le fichier app/Model/ContactFacade.php :
namespace App\Model;
use Nette\Mail\Mailer;
use Nette\Mail\Message;
class ContactFacade
{
public function __construct(
private Mailer $mailer,
) {
}
public function sendMessage(string $email, string $name, string $message): void
{
$mail = new Message;
$mail->addTo('admin@example.com') // votre e-mail
->setFrom($email, $name)
->setSubject('Message du formulaire de contact')
->setBody($message);
$this->mailer->send($mail);
}
}
La méthode sendMessage() crée et envoie l'e-mail. Elle utilise pour cela un service mailer, qu'elle reçoit
comme dépendance par le constructeur. Pour en savoir plus, voir l'envoi
d'e-mails.
Revenons maintenant au presenter et complétons la méthode contactFormSucceeded(). Elle appellera la méthode
sendMessage() de la classe ContactFacade en lui passant les données soumises par le formulaire. Et
comment obtenir l'objet ContactFacade ? Nous le demanderons par le constructeur, grâce à l'injection de
dépendances :
use App\Model\ContactFacade;
use Nette\Application\UI\Form;
use Nette\Application\UI\Presenter;
class HomePresenter extends Presenter
{
public function __construct(
private ContactFacade $facade,
) {
}
protected function createComponentContactForm(): Form
{
// ...
}
public function contactFormSucceeded(stdClass $data): void
{
$this->facade->sendMessage($data->email, $data->name, $data->message);
$this->flashMessage('Le message a été envoyé');
$this->redirect('this');
}
}
Après l'envoi de l'e-mail, nous affichons à l'utilisateur un message flash qui confirme l'envoi. Puis nous redirigeons pour éviter que le formulaire ne soit renvoyé par un rafraîchissement du navigateur.
Si tout est bien en place, vous devriez donc maintenant pouvoir envoyer un e-mail depuis votre formulaire de contact. Félicitations !
Template HTML de l'e-mail
Pour l'instant, c'est un e-mail en texte brut, contenant seulement le message envoyé par le formulaire, qui est expédié.
Nous pouvons cependant utiliser du HTML dans l'e-mail pour rendre son apparence plus attrayante. Nous en créerons un template en
Latte et l'enregistrerons sous app/Model/contactEmail.latte :
<html>
<title>Message du formulaire de contact</title>
<body>
<p><strong>Nom :</strong> {$name}</p>
<p><strong>E-mail :</strong> {$email}</p>
<p><strong>Message :</strong> {$message}</p>
</body>
</html>
Il reste à modifier ContactFacade pour qu'elle utilise ce template. Dans le constructeur, nous demanderons la
classe LatteFactory, qui sait créer un objet Latte\Engine, le moteur de rendu des templates Latte. À l'aide de la
méthode renderToString(), nous rendons le template dans une chaîne. Le premier paramètre est le chemin du fichier
de template, le second un tableau de variables à lui passer.
namespace App\Model;
use Nette\Bridges\ApplicationLatte\LatteFactory;
use Nette\Mail\Mailer;
use Nette\Mail\Message;
class ContactFacade
{
public function __construct(
private Mailer $mailer,
private LatteFactory $latteFactory,
) {
}
public function sendMessage(string $email, string $name, string $message): void
{
$latte = $this->latteFactory->create();
$body = $latte->renderToString(__DIR__ . '/contactEmail.latte', [
'email' => $email,
'name' => $name,
'message' => $message,
]);
$mail = new Message;
$mail->addTo('admin@example.com') // votre e-mail
->setFrom($email, $name)
->setHtmlBody($body);
$this->mailer->send($mail);
}
}
Nous passons ensuite le contenu HTML généré de l'e-mail à la méthode setHtmlBody() au lieu du
setBody() d'origine. Nous n'avons pas non plus besoin d'indiquer le sujet de l'e-mail avec setSubject(),
car la bibliothèque l'extrait automatiquement de l'élément <title> du template.
Configuration
Dans le code de la classe ContactFacade, notre e-mail d'administrateur admin@example.com est toujours
écrit en dur. Il vaudrait mieux le déplacer dans le fichier de configuration. Comment faire ?
Modifions d'abord la classe ContactFacade en remplaçant la chaîne d'e-mail écrite en dur par une variable
passée au constructeur :
class ContactFacade
{
public function __construct(
private Mailer $mailer,
private LatteFactory $latteFactory,
private string $adminEmail,
) {
}
public function sendMessage(string $email, string $name, string $message): void
{
// ...
$mail = new Message;
$mail->addTo($this->adminEmail)
->setFrom($email, $name)
->setHtmlBody($body);
// ...
}
}
La deuxième étape consiste à fournir la valeur de cette variable dans la configuration. Dans le fichier
app/config/services.neon, ajoutez :
services:
- App\Model\ContactFacade(adminEmail: admin@example.com)
Et voilà. Si la section services contient beaucoup d'entrées et que vous avez l'impression que l'adresse e-mail
s'y perd, nous pouvons en faire un paramètre. Modifiez l'entrée ainsi :
services:
- App\Model\ContactFacade(adminEmail: %adminEmail%)
Et définissez ce paramètre dans le fichier app/config/common.neon :
parameters:
adminEmail: admin@example.com
Et c'est terminé !