Créons un formulaire de contact

Voyons comment créer un formulaire de contact dans Nette, y compris l'envoi vers un e-mail. C'est parti !

Tout d'abord, nous devons créer un nouveau projet. Comme l'explique la page " Getting Started". Ensuite, nous pouvons commencer à créer le formulaire.

La manière la plus simple est de créer le formulaire directement dans Presenter. Nous pouvons utiliser le formulaire préétabli HomePresenter. Nous ajouterons le composant contactForm représentant le formulaire. Pour ce faire, nous écrivons la méthode d'usine createComponentContactForm() dans le code qui produira 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', 'Name:')
			->setRequired('Enter your name');
		$form->addEmail('email', 'E-mail:')
			->setRequired('Enter your e-mail');
		$form->addTextarea('message', 'Message:')
			->setRequired('Enter message');
		$form->addSubmit('send', 'Send');
		$form->onSuccess[] = [$this, 'contactFormSucceeded'];
		return $form;
	}

	public function contactFormSucceeded(Form $form, $data): void
	{
		// sending an email
	}
}

Comme vous pouvez le voir, nous avons créé deux méthodes. La première méthode createComponentContactForm() crée un nouveau formulaire. Celui-ci comporte des champs pour le nom, l'adresse électronique et le message, que nous ajoutons à l'aide des méthodes addText(), addEmail() et addTextArea(). Nous avons également ajouté un bouton pour soumettre le formulaire. Mais que se passe-t-il si l'utilisateur ne remplit pas certains champs ? Dans ce cas, nous devons l'informer qu'il s'agit d'un champ obligatoire. C'est ce que nous avons fait avec la méthode setRequired(). Enfin, nous avons également ajouté un événement onSuccess, qui est déclenché si le formulaire est soumis avec succès. Dans notre cas, il appelle la méthode contactFormSucceeded, qui se charge de traiter le formulaire soumis. Nous l'ajouterons au code dans un instant.

Laissez le composant contantForm être rendu dans le modèle templates/Home/default.latte:

{block content}
<h1>Contant Form</h1>
{control contactForm}

Pour envoyer le courrier électronique lui-même, nous créons une nouvelle classe appelée ContactFacade et la plaçons dans le fichier app/Model/ContactFacade.php:

<?php
declare(strict_types=1);

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') // your email
			->setFrom($email, $name)
			->setSubject('Message from the contact form')
			->setBody($message);

		$this->mailer->send($mail);
	}
}

La méthode sendMessage() créera et enverra le courrier électronique. Pour ce faire, elle utilise ce que l'on appelle un “mailer”, qu'elle transmet en tant que dépendance via le constructeur. En savoir plus sur l'envoi de courriels.

Nous allons maintenant retourner au présentateur et compléter la méthode contactFormSucceeded(). Elle appelle la méthode sendMessage() de la classe ContactFacade et lui transmet les données du formulaire. Et comment obtenir l'objet ContactFacade? Il nous sera transmis par le constructeur :

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('The message has been sent');
		$this->redirect('this');
	}
}

Après l'envoi du courrier électronique, nous montrons à l'utilisateur le " message flash", qui confirme que le message a été envoyé, puis nous le redirigeons vers la page suivante, de sorte que le formulaire ne puisse pas être soumis à nouveau en utilisant la fonction refresh du navigateur.

Si tout fonctionne, vous devriez être en mesure d'envoyer un courriel à partir de votre formulaire de contact. Nous vous félicitons !

Modèle d'e-mail HTML

Pour l'instant, un courriel en texte brut contenant uniquement le message envoyé par le formulaire est envoyé. Mais nous pouvons utiliser le HTML dans l'e-mail et le rendre plus attrayant. Nous allons créer un modèle dans Latte, que nous enregistrerons dans app/Model/contactEmail.latte:

<html>
	<title>Message from the contact form</title>

	<body>
		<p><strong>Name:</strong> {$name}</p>
		<p><strong>E-mail:</strong> {$email}</p>
		<p><strong>Message:</strong> {$message}</p>
	</body>
</html>

Il reste à modifier ContactFacade pour utiliser ce modèle. Dans le constructeur, nous demandons la classe LatteFactory, qui peut produire l'objet Latte\Engine, un moteur de rendu de modèle Latte. Nous utilisons la méthode renderToString() pour rendre le modèle dans un fichier, le premier paramètre étant le chemin vers le modèle et le second les variables.

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') // your email
			->setFrom($email, $name)
			->setHtmlBody($body);

		$this->mailer->send($mail);
	}
}

Nous passons ensuite l'e-mail HTML généré à la méthode setHtmlBody() au lieu de l'original setBody(). Nous n'avons pas non plus besoin de spécifier le sujet de l'e-mail dans setSubject(), car la bibliothèque l'extrait de l'élément <title> dans le modèle.

Configuration de

Dans le code de la classe ContactFacade, notre email d'administration admin@example.com est encore codé en dur. Il serait préférable de la déplacer dans le fichier de configuration. Comment faire ?

Tout d'abord, nous modifions la classe ContactFacade et remplaçons la chaîne de l'email par une variable passée par le 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);
		// ...
	}
}

Et la deuxième étape consiste à mettre la valeur de cette variable dans la configuration. Dans le fichier app/config/services.neon nous ajoutons :

services:
	- App\Model\ContactFacade(adminEmail: admin@example.com)

Et c'est tout. S'il y a beaucoup d'éléments dans la section services et que vous avez l'impression que le courriel se perd parmi eux, nous pouvons en faire une variable. Nous modifierons l'entrée en :

services:
	- App\Model\ContactFacade(adminEmail: %adminEmail%)

et définir cette variable dans le fichier app/config/common.neon:

parameters:
	adminEmail: admin@example.com

Et c'est fait !