Creazione di un modulo di contatto
Vediamo come creare un modulo di contatto in Nette, compreso l'invio di email. Allora, iniziamo!
Prima di tutto, dobbiamo creare un nuovo progetto. Come farlo è spiegato nella pagina Iniziare. E poi possiamo iniziare a creare il modulo.
Il modo più semplice è creare il modulo direttamente nel presenter.
Possiamo utilizzare il HomePresenter
pre-preparato. Aggiungeremo ad esso il componente contactForm
che
rappresenta il modulo. Lo faremo scrivendo nel codice il metodo factory createComponentContactForm()
, 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', 'Nome:')
->setRequired('Inserisci il nome');
$form->addEmail('email', 'E-mail:')
->setRequired('Inserisci l\'e-mail');
$form->addTextarea('message', 'Messaggio:')
->setRequired('Inserisci il messaggio');
$form->addSubmit('send', 'Invia');
$form->onSuccess[] = [$this, 'contactFormSucceeded'];
return $form;
}
public function contactFormSucceeded(Form $form, $data): void
{
// invio dell'email
}
}
Come potete vedere, abbiamo creato due metodi. Il primo metodo createComponentContactForm()
crea un nuovo modulo.
Questo ha campi per nome, email e messaggio, che aggiungiamo con i metodi addText()
, addEmail()
e
addTextArea()
. Abbiamo anche aggiunto un pulsante per inviare il modulo. Ma cosa succede se l'utente non compila
qualche campo? In tal caso, dovremmo fargli sapere che è un campo obbligatorio. Abbiamo ottenuto questo risultato con il metodo
setRequired()
. Infine, abbiamo aggiunto anche l'evento
onSuccess
, che si attiva se il modulo viene inviato con successo. Nel nostro caso, chiama il metodo
contactFormSucceeded
, che si occuperà dell'elaborazione del modulo inviato. Lo aggiungeremo al codice tra un
momento.
Faremo renderizzare il componente contactForm
nel template Home/default.latte
:
{block content}
<h1>Modulo di contatto</h1>
{control contactForm}
Per l'invio effettivo dell'email, creeremo una nuova classe che chiameremo ContactFacade
e la posizioneremo 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') // la tua email
->setFrom($email, $name)
->setSubject('Messaggio dal modulo di contatto')
->setBody($message);
$this->mailer->send($mail);
}
}
Il metodo sendMessage()
crea e invia l'email. Utilizza a tal fine il cosiddetto mailer, che si fa passare come
dipendenza tramite il costruttore. Leggete di più sull'invio di email.
Ora torniamo al presenter e completiamo il metodo contactFormSucceeded()
. Questo chiamerà il metodo
sendMessage()
della classe ContactFacade
e gli passerà i dati del modulo. E come otteniamo l'oggetto
ContactFacade
? Ce lo facciamo passare tramite 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('Il messaggio è stato inviato');
$this->redirect('this');
}
}
Dopo l'invio dell'email, mostreremo ancora all'utente il cosiddetto flash message, confermando che il messaggio è stato inviato, e poi reindirizzeremo a un'altra pagina, in modo che non sia possibile inviare nuovamente il modulo tramite refresh nel browser.
Bene, e se tutto funziona, dovreste essere in grado di inviare un'email dal vostro modulo di contatto. Congratulazioni!
Template HTML dell'email
Per ora viene inviata un'email di testo semplice contenente solo il messaggio inviato dal modulo. Ma nell'email possiamo
utilizzare HTML e renderne l'aspetto più attraente. Creeremo per essa un template in Latte, che scriveremo in
app/Model/contactEmail.latte
:
<html>
<title>Messaggio dal modulo di contatto</title>
<body>
<p><strong>Nome:</strong> {$name}</p>
<p><strong>E-mail:</strong> {$email}</p>
<p><strong>Messaggio:</strong> {$message}</p>
</body>
</html>
Resta da modificare ContactFacade
affinché utilizzi questo template. Nel costruttore richiederemo la classe
LatteFactory
, che sa produrre l'oggetto Latte\Engine
, ovvero il renderizzatore di template Latte. Tramite il metodo
renderToString()
renderizzeremo 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') // la tua email
->setFrom($email, $name)
->setHtmlBody($body);
$this->mailer->send($mail);
}
}
L'email HTML generata la passeremo quindi al metodo setHtmlBody()
invece dell'originale setBody()
.
Inoltre, non dobbiamo specificare l'oggetto dell'email in setSubject()
, perché la libreria lo prenderà
dall'elemento <title>
del template.
Configurazione
Nel codice della classe ContactFacade
è ancora hardcoded la nostra email di amministratore
admin@example.com
. Sarebbe meglio spostarla nel file di configurazione. Come fare?
Prima modifichiamo la classe ContactFacade
e sostituiamo la stringa con l'email con una variabile passata tramite
il 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);
// ...
}
}
E il secondo passo è specificare il valore di questa variabile nella configurazione. Nel file
app/config/services.neon
scriviamo:
services:
- App\Model\ContactFacade(adminEmail: admin@example.com)
Ed è fatto. Se ci fossero molte voci nella sezione services
e aveste la sensazione che l'email si perda tra di
esse, possiamo trasformarla in una variabile. Modifichiamo la scrittura in:
services:
- App\Model\ContactFacade(adminEmail: %adminEmail%)
E nel file app/config/common.neon
definiamo questa variabile:
parameters:
adminEmail: admin@example.com
Ed è fatto!