Nette Documentation Preview

syntax
Creiamo un modulo di contatto
*****************************

.[perex]
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 |nette:installation]. Poi possiamo iniziare a creare il modulo.

Il modo più semplice è creare il [modulo direttamente in Presenter |forms: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:

```php
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 |nette:glossary#events] `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 `templates/Home/default.latte`:

```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
<?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 |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:

```php
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 |application:components#flash-messages], 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 .[#toc-html-email-template]
--------------------------------------------------

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`:

```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 |latte:develop#how-to-render-a-template]. Utilizziamo il metodo `renderToString()` per rendere il template in un file; il primo parametro è il percorso del template e il secondo sono le variabili.

```php
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 .[#toc-configuring]
-------------------------------------

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:

```php
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:

```neon
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:

```neon
services:
	- App\Model\ContactFacade(adminEmail: %adminEmail%)
```

E definiamo questa variabile nel file `app/config/common.neon`:

```neon
parameters:
	adminEmail: admin@example.com
```

Ed è fatta!


{{sitename: Migliori pratiche}}

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 templates/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!