Creiamo un modulo di contatto
Vediamo come creare un modulo di contatto in Nette, compreso l'invio a un'e-mail. Allora, facciamolo!
Per prima cosa dobbiamo creare un nuovo progetto. Come spiega la pagina introduttiva. Poi possiamo iniziare a creare il modulo.
Il modo più semplice è creare il modulo direttamente in Presenter.
Possiamo utilizzare il componente preconfezionato HomePresenter
. Aggiungeremo il componente contactForm
che rappresenta il modulo. Per farlo, scriviamo il metodo createComponentContactForm()
factory nel codice che
produrrà il componente:
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
}
}
Come si può vedere, abbiamo creato due metodi. Il primo metodo createComponentContactForm()
crea un nuovo modulo.
Questo ha campi per il nome, l'email e il messaggio, che vengono aggiunti con i metodi addText()
,
addEmail()
e addTextArea()
. Abbiamo anche aggiunto un pulsante per inviare il modulo. Ma cosa succede se
l'utente non compila alcuni campi? In questo caso, dovremmo fargli sapere che si tratta di un campo obbligatorio. Lo abbiamo fatto
con il metodo setRequired()
. Infine, abbiamo aggiunto anche un evento onSuccess
, che si attiva se il form viene inviato con
successo. Nel nostro caso, richiama il metodo contactFormSucceeded
, che si occupa di elaborare il modulo inviato. Lo
aggiungeremo al codice tra poco.
Il componente contantForm
deve essere reso nel template Home/default.latte
:
{block content}
<h1>Contant Form</h1>
{control contactForm}
Per inviare l'e-mail stessa, creiamo una nuova classe chiamata ContactFacade
e la inseriamo nel file
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);
}
}
Il metodo sendMessage()
creerà e invierà l'email. Per farlo, utilizza un cosiddetto mailer, che passa come
dipendenza attraverso il costruttore. Per saperne di più sull'invio di e-mail.
Ora, torniamo al presentatore e completiamo il metodo contactFormSucceeded()
. Richiama il metodo
sendMessage()
della classe ContactFacade
e gli passa i dati del modulo. Come si ottiene l'oggetto
ContactFacade
? Ce lo passerà il costruttore:
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');
}
}
Dopo l'invio dell'e-mail, mostriamo all'utente il cosiddetto messaggio flash, che conferma l'invio del messaggio, e poi reindirizziamo alla pagina successiva, in modo che il modulo non possa essere ripresentato usando refresh nel browser.
Se tutto funziona, dovreste essere in grado di inviare un'e-mail dal vostro modulo di contatto. Congratulazioni!
Modello di e-mail HTML
Per ora, viene inviata un'e-mail di testo semplice contenente solo il messaggio inviato dal modulo. Ma possiamo usare l'HTML
nell'e-mail e renderla più attraente. Creeremo un modello in Latte, che salveremo in
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>
Resta da modificare ContactFacade
per utilizzare questo modello. Nel costruttore, richiediamo la classe
LatteFactory
, che può produrre l'oggetto Latte\Engine
, un renderizzatore di template di Latte. Utilizziamo il
metodo renderToString()
per rendere il template in un file; il primo parametro è il percorso del template e il
secondo sono le variabili.
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);
}
}
Passiamo poi l'email HTML generata al metodo setHtmlBody()
, invece del metodo originale setBody()
.
Non è necessario specificare l'oggetto dell'email in setSubject()
, perché la libreria lo prende dall'elemento
<title>
nel template.
Configurazione di
Nel codice della classe ContactFacade
, l'email di amministrazione admin@example.com
è ancora
codificata in modo rigido. Sarebbe meglio spostarla nel file di configurazione. Come fare?
Per prima cosa, modifichiamo la classe ContactFacade
e sostituiamo la stringa dell'email con una variabile passata
dal costruttore:
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);
// ...
}
}
Il secondo passo consiste nell'inserire il valore di questa variabile nella configurazione. Nel file
app/config/services.neon
aggiungiamo:
services:
- App\Model\ContactFacade(adminEmail: admin@example.com)
E questo è tutto. Se ci sono molte voci nella sezione services
e si ha la sensazione che l'e-mail si perda tra di
esse, possiamo renderla una variabile. Modificheremo la voce in:
services:
- App\Model\ContactFacade(adminEmail: %adminEmail%)
E definiamo questa variabile nel file app/config/common.neon
:
parameters:
adminEmail: admin@example.com
Ed è fatta!