Vytváříme kontaktní formulář
Podíváme se na to, jak v Nette vytvořit kontaktní formulář včetně odesílání na email. Tak tedy do toho!
Nejprve musíme vytvořit nový projekt. Jak na to vysvětluje stránka Začínáme. A pak už můžeme začít s tvorbou formuláře.
Nejjednodušší je vytvoření formuláře přímo v presenteru.
Můžeme využít předpřipravený HomePresenter
. Do něj přidáme komponentu contactForm
představující formulář. Uděláme to tak, že do kódu zapíšeme tovární metodu createComponentContactForm()
,
která komponentu vyrobí:
use Nette\Application\UI\Form;
use Nette\Application\UI\Presenter;
class HomePresenter extends Presenter
{
protected function createComponentContactForm(): Form
{
$form = new Form;
$form->addText('name', 'Jméno:')
->setRequired('Zadejte jméno');
$form->addEmail('email', 'E-mail:')
->setRequired('Zadejte e-mail');
$form->addTextarea('message', 'Zpráva:')
->setRequired('Zadejte zprávu');
$form->addSubmit('send', 'Odeslat');
$form->onSuccess[] = [$this, 'contactFormSucceeded'];
return $form;
}
public function contactFormSucceeded(Form $form, $data): void
{
// odeslání emailu
}
}
Jak vidíte, vytvořili jsme dvě metody. První metoda createComponentContactForm()
vytváří nový formulář.
Ten má políčka pro jméno, email a zprávu, která přidáváme metodami addText()
, addEmail()
a
addTextArea()
. Také jsme přidali tlačítko pro odeslání formuláře. Ale co když uživatel nevyplní nějaké
pole? V takovém případě bychom mu měli dát vědět, že je to povinné pole. Toho jsme docílili metodou
setRequired()
. Nakonec jsme přidali také událost
onSuccess
, která se spustí, pokud je formulář úspěšně odeslán. V našem případě zavolá metodu
contactFormSucceeded
, která se postará o zpracování odeslaného formuláře. To do kódu doplníme za
okamžik.
Komponentu contantForm
necháme vykreslit v šabloně Home/default.latte
:
{block content}
<h1>Kontantní formulář</h1>
{control contactForm}
Pro samotné odeslání emailu vytvoříme novou třídu, kterou nazveme ContactFacade
a umístíme ji do souboru
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') // váš email
->setFrom($email, $name)
->setSubject('Zpráva z kontaktního formuláře')
->setBody($message);
$this->mailer->send($mail);
}
}
Metoda sendMessage()
vytvoří a odešle email. Využívá k tomu tzv. mailer, který si nechá předat jako
závislost přes konstruktor. Přečtete si více o odesílání emailů.
Nyní se vrátíme zpátky k presenteru a dokončíme metodu contactFormSucceeded()
. Ta zavolá metodu
sendMessage()
třídy ContactFacade
a předá jí údaje z formuláře. A jak získáme objekt
ContactFacade
? Necháme si jej předat konstruktorem:
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('Zpráva byla odeslána');
$this->redirect('this');
}
}
Poté, co se email odešle, ještě zobrazíme uživateli tzv. flash message, potvrzující, že zpráva se odeslala, a poté přesměrujeme na další stránku, aby nebylo možné formulář opakovaně odeslat pomocí refresh v prohlížeči.
Tak, a pokud všechno funguje, měli byste být schopni odeslat email z vašeho kontaktního formuláře. Gratuluji!
HTML šablona emailu
Zatím se odesílá prostý textový email obsahující pouze zprávu odeslanou formulářem. V emailu ale můžeme využít
HTML a udělat jeho podobu atraktivnější. Vytvoříme pro něj šablonu v Latte, kterou zapíšeme do
app/Model/contactEmail.latte
:
<html>
<title>Zpráva z kontaktního formuláře</title>
<body>
<p><strong>Jméno:</strong> {$name}</p>
<p><strong>E-mail:</strong> {$email}</p>
<p><strong>Zpráva:</strong> {$message}</p>
</body>
</html>
Zbývá upravit ContactFacade
, aby tuto šablonu používal. V konstruktoru si vyžádáme třídu
LatteFactory
, která umí vyrobit objekt Latte\Engine
, tedy vykreslovač Latte šablon. Pomocí metody
renderToString()
šablonu vykreslíme do souboru, prvním parametrem je cesta k šabloně a druhým jsou
proměnné.
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') // váš email
->setFrom($email, $name)
->setHtmlBody($body);
$this->mailer->send($mail);
}
}
Vygenerovaný HTML email pak předáme metodě setHtmlBody()
místo původní setBody()
. Taktéž
nemusíme uvádět předmět emailu v setSubject()
, protože si jej knihovna vezme z elementu
<title>
šablony.
Konfigurace
V kódu třídy ContactFacade
je pořád natvrdo zapsaný náš administrátorský email
admin@example.com
. Bylo by lepší jej přesunout do konfiguračního souboru. Jak na to?
Nejprve upravíme třídu ContactFacade
a řetězec s emailem nahradíme proměnnou předanou konstruktorem:
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 druhým krokem je uvedení hodnoty této proměnné v konfiguraci. Do souboru app/config/services.neon
zapíšeme:
services:
- App\Model\ContactFacade(adminEmail: admin@example.com)
A je to. Pokud by položek v sekci services
bylo hodně a měli byste pocit, že email se mezi nimi ztrácí,
můžeme z něj udělat proměnnou. Upravíme zápis na:
services:
- App\Model\ContactFacade(adminEmail: %adminEmail%)
A v souboru app/config/common.neon
nadefinujeme tuto proměnnou:
parameters:
adminEmail: admin@example.com
A je hotovo!