Stwórzmy formularz kontaktowy
Zobaczmy, jak w Nette utworzyć formularz kontaktowy wraz z wysyłaniem wpisanych danych e-mailem. No to do dzieła!
Najpierw musimy utworzyć nowy projekt. Jak to zrobić, wyjaśnia strona Pierwsze kroki. Potem możemy zabrać się za tworzenie formularza.
Najprostszym podejściem jest utworzenie formularza bezpośrednio w
presenterze. Możemy wykorzystać przygotowany HomePresenter. Dodamy do niego komponent contactForm
reprezentujący nasz formularz. Zrobimy to, dopisując do kodu presentera metodę fabrykującą
createComponentContactForm(), która ten komponent utworzy:
use Nette\Application\UI\Form;
use Nette\Application\UI\Presenter;
class HomePresenter extends Presenter
{
protected function createComponentContactForm(): Form
{
$form = new Form;
$form->addText('name', 'Imię:')
->setRequired('Podaj swoje imię');
$form->addEmail('email', 'E-mail:')
->setRequired('Podaj swój e-mail');
$form->addTextArea('message', 'Wiadomość:')
->setRequired('Wpisz wiadomość');
$form->addSubmit('send', 'Wyślij');
$form->onSuccess[] = $this->contactFormSucceeded(...);
return $form;
}
private function contactFormSucceeded(Form $form, $data): void
{
// wysłanie e-maila
}
}
Jak widzisz, utworzyliśmy dwie metody. Pierwsza z nich, createComponentContactForm(), tworzy nową instancję
formularza. Zawiera pola na imię, e-mail i wiadomość, dodane odpowiednio metodami addText(),
addEmail() i addTextArea(). Dodaliśmy też przycisk wysyłający. A co, jeśli użytkownik zostawi
któreś pole puste? W takim razie powinniśmy go poinformować, że pole jest wymagane. Osiągnęliśmy to metodą
setRequired(). Na koniec podpięliśmy jeszcze handler zdarzenia onSuccess, które wywołuje się po udanym
wysłaniu formularza. W naszym przypadku wywołuje on metodę contactFormSucceeded, która zajmie się przetworzeniem
wysłanych danych. Za chwilę ją uzupełnimy.
Komponent contactForm wyrenderujmy w szablonie Home/default.latte:
{block content}
<h1>Formularz kontaktowy</h1>
{control contactForm}
Do samego wysyłania e-maila utworzymy nową klasę o nazwie ContactFacade i umieścimy ją w pliku
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') // Twój e-mail
->setFrom($email, $name)
->setSubject('Wiadomość z formularza kontaktowego')
->setBody($message);
$this->mailer->send($mail);
}
}
Metoda sendMessage() tworzy i wysyła e-mail. Wykorzystuje do tego usługę mailera, którą otrzymuje jako
zależność przez konstruktor. Przeczytaj więcej o wysyłaniu e-maili.
Wróćmy teraz do presentera i uzupełnijmy metodę contactFormSucceeded(). Wywoła ona metodę
sendMessage() klasy ContactFacade i przekaże jej dane wysłane formularzem. A skąd weźmiemy obiekt
ContactFacade? Poprosimy o niego w konstruktorze za pomocą wstrzykiwania zależności:
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('Wiadomość została wysłana');
$this->redirect('this');
}
}
Po wysłaniu e-maila wyświetlimy użytkownikowi wiadomość flash potwierdzającą wysłanie. A następnie przekierujemy, żeby formularz nie dało się wysłać ponownie odświeżeniem strony w przeglądarce.
No i jeśli wszystko jest ustawione poprawnie, powinieneś już móc wysłać e-mail ze swojego formularza kontaktowego. Gratulacje!
Szablon e-maila w HTML
Na razie wysyła się zwykły e-mail tekstowy zawierający tylko wiadomość wysłaną formularzem. W e-mailu możemy jednak
użyć HTML-a i uatrakcyjnić jego wygląd. Utworzymy dla niego szablon w Latte i zapiszemy go jako
app/Model/contactEmail.latte:
<html>
<title>Wiadomość z formularza kontaktowego</title>
<body>
<p><strong>Imię:</strong> {$name}</p>
<p><strong>E-mail:</strong> {$email}</p>
<p><strong>Wiadomość:</strong> {$message}</p>
</body>
</html>
Pozostaje zmodyfikować ContactFacade tak, żeby ten szablon wykorzystywała. W konstruktorze poprosimy o klasę
LatteFactory, która potrafi utworzyć obiekt Latte\Engine, czyli renderer szablonów Latte. Metodą
renderToString() wyrenderujemy szablon do ciągu znaków. Pierwszym parametrem jest ścieżka do pliku szablonu,
drugim tablica zmiennych, które mu przekazujemy.
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') // Twój e-mail
->setFrom($email, $name)
->setHtmlBody($body);
$this->mailer->send($mail);
}
}
Wygenerowaną treść e-maila w HTML przekazujemy potem metodzie setHtmlBody() zamiast pierwotnej
setBody(). Nie musimy też podawać tematu e-maila metodą setSubject(), bo biblioteka pobiera go
automatycznie z elementu <title> w szablonie.
Konfigurowanie
W kodzie klasy ContactFacade nadal mamy zapisany na sztywno e-mail administratora admin@example.com.
Lepiej byłoby przenieść go do pliku konfiguracyjnego. Jak to zrobić?
Najpierw zmodyfikujemy klasę ContactFacade i zamiast zapisanego na sztywno ciągu z e-mailem użyjemy zmiennej
przekazanej przez konstruktor:
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);
// ...
}
}
Drugim krokiem jest podanie wartości tej zmiennej w konfiguracji. Do pliku app/config/services.neon
dopiszemy:
services:
- App\Model\ContactFacade(adminEmail: admin@example.com)
I to wszystko. Jeśli pozycji w sekcji services jest dużo i masz wrażenie, że adres e-mail się wśród nich
gubi, możemy zrobić z niego parametr. Zmodyfikujemy wpis tak:
services:
- App\Model\ContactFacade(adminEmail: %adminEmail%)
A ten parametr zdefiniujemy w pliku app/config/common.neon:
parameters:
adminEmail: admin@example.com
I gotowe!