Tworzymy formularz kontaktowy
Zobaczymy, jak w Nette stworzyć formularz kontaktowy, w tym wysyłanie na e-mail. Zatem do dzieła!
Najpierw musimy stworzyć nowy projekt. Jak to zrobić, wyjaśnia strona Pierwsze kroki. A potem już możemy zacząć tworzyć formularz.
Najprościej jest stworzyć formularz bezpośrednio w prezenterze.
Możemy wykorzystać przygotowany HomePresenter
. Dodamy do niego komponent contactForm
reprezentujący
formularz. Zrobimy to tak, że do kodu wpiszemy metodę fabryczną createComponentContactForm()
, która wyprodukuje
komponent:
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('Proszę podać imię');
$form->addEmail('email', 'E-mail:')
->setRequired('Proszę podać e-mail');
$form->addTextarea('message', 'Wiadomość:')
->setRequired('Proszę wpisać wiadomość');
$form->addSubmit('send', 'Wyślij');
$form->onSuccess[] = [$this, 'contactFormSucceeded'];
return $form;
}
public function contactFormSucceeded(Form $form, $data): void
{
// wysłanie e-maila
}
}
Jak widzisz, stworzyliśmy dwie metody. Pierwsza metoda createComponentContactForm()
tworzy nowy formularz. Ma on
pola na imię, e-mail i wiadomość, które dodajemy metodami addText()
, addEmail()
i
addTextArea()
. Dodaliśmy również przycisk do wysłania formularza. Ale co jeśli użytkownik nie wypełni
jakiegoś pola? W takim przypadku powinniśmy go poinformować, że jest to pole obowiązkowe. Osiągnęliśmy to metodą
setRequired()
. Na koniec dodaliśmy również zdarzenie
onSuccess
, które uruchamia się, jeśli formularz zostanie pomyślnie wysłany i jest poprawny. W naszym przypadku
wywołuje metodę contactFormSucceeded
, która zajmie się przetwarzaniem wysłanego formularza. Uzupełnimy to w
kodzie za chwilę.
Komponent contactForm
wyrenderujemy w szablonie Home/default.latte
:
{block content}
<h1>Formularz kontaktowy</h1>
{control contactForm}
Do samego wysłania e-maila stworzymy nową klasę, którą nazwiemy ContactFacade
i umieścimy ją w pliku
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') // 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 tzw. mailer, który przyjmuje jako
zależność przez konstruktor. Przeczytaj więcej o wysyłaniu e-maili.
Teraz wrócimy do presentera i dokończymy metodę contactFormSucceeded()
. Wywoła ona metodę
sendMessage()
klasy ContactFacade
i przekaże jej dane z formularza. A jak uzyskać obiekt
ContactFacade
? Przyjmiemy go przez konstruktor:
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 jeszcze wyświetlimy użytkownikowi tzw. flash message, potwierdzającą, że wiadomość została wysłana, a następnie przekierujemy z powrotem na tę samą stronę, aby nie było możliwe ponowne wysłanie formularza za pomocą refresh w przeglądarce.
Tak, i jeśli wszystko działa, powinieneś być w stanie wysłać e-mail z twojego formularza kontaktowego. Gratulacje!
Szablon HTML e-maila
Na razie wysyłany jest prosty tekstowy e-mail zawierający tylko wiadomość wysłaną formularzem. W e-mailu możemy jednak
wykorzystać HTML i uczynić jego wygląd bardziej atrakcyjnym. Stworzymy dla niego szablon w Latte, który zapiszemy w
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
, aby używał tego szablonu. W konstruktorze zażądamy klasy
LatteFactory
, która potrafi stworzyć obiekt Latte\Engine
, czyli renderera szablonów Latte. Za pomocą metody
renderToString()
wyrenderujemy szablon do stringa, pierwszym parametrem jest ścieżka do szablonu, a drugim są
parametry.
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);
}
}
Wygenerowany e-mail HTML przekażemy następnie metodzie setHtmlBody()
zamiast pierwotnej setBody()
.
Również nie musimy podawać tematu e-maila w setSubject()
, ponieważ biblioteka pobierze go z elementu
<title>
szablonu.
Konfiguracja
W kodzie klasy ContactFacade
nadal jest na sztywno zapisany nasz e-mail administratora
admin@example.com
. Lepiej byłoby przenieść go do pliku konfiguracyjnego. Jak to zrobić?
Najpierw zmodyfikujemy klasę ContactFacade
i ciąg znaków z e-mailem zastąpimy zmienną przekazaną 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);
// ...
}
}
A drugim krokiem jest podanie wartości tej zmiennej w konfiguracji. Do pliku app/config/services.neon
zapiszemy:
services:
- App\Model\ContactFacade(adminEmail: admin@example.com)
I to wszystko. Jeśli pozycji w sekcji services
byłoby dużo i mielibyście wrażenie, że e-mail ginie wśród
nich, możemy uczynić go parametrem. Zmodyfikujemy zapis na:
services:
- App\Model\ContactFacade(adminEmail: %adminEmail%)
A w pliku app/config/common.neon
zdefiniujemy tę zmienną:
parameters:
adminEmail: admin@example.com
I gotowe!