Nette Documentation Preview

syntax
Vamos criar um formulário de contato
************************************

.[perex]
Vamos ver como criar um formulário de contato em Nette, inclusive enviando-o para um e-mail. Então, vamos fazer isso!

Primeiro temos que criar um novo projeto. Como explica a página [Primeiros Pass |nette:installation] os. E depois podemos começar a criar o formulário.

A maneira mais fácil é criar o [formulário diretamente no Apresentador |forms:in-presenter]. Podemos usar o pré-fabricado `HomePresenter`. Acrescentaremos o componente `contactForm` que representa o formulário. Fazemos isso escrevendo o método de fábrica `createComponentContactForm()` no código que irá produzir o 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
	}
}
```

Como você pode ver, nós criamos dois métodos. O primeiro método `createComponentContactForm()` cria uma nova forma. Este tem campos para nome, e-mail e mensagem, que adicionamos usando os métodos `addText()`, `addEmail()` e `addTextArea()`. Também adicionamos um botão para enviar o formulário.
Mas e se o usuário não preencher alguns campos? Nesse caso, devemos avisá-lo que se trata de um campo obrigatório. Fizemos isso com o método `setRequired()`.
Finalmente, adicionamos também um [evento |nette:glossary#events] `onSuccess`, que é acionado se o formulário for submetido com sucesso. Em nosso caso, ele chama o método `contactFormSucceeded`, que se encarrega de processar o formulário submetido. Acrescentaremos isso ao código em um momento.

Deixe o componente `contantForm` ser apresentado no modelo `Home/default.latte`:

```latte
{block content}
<h1>Contant Form</h1>
{control contactForm}
```

Para enviar o e-mail em si, criamos uma nova classe chamada `ContactFacade` e a colocamos no arquivo `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);
	}
}
```

O método `sendMessage()` irá criar e enviar o e-mail. Para isso, ele usa o chamado mailer, que passa como uma dependência através do construtor. Leia mais sobre o [envio de e-mails |mail:].

Agora, vamos voltar ao apresentador e completar o método `contactFormSucceeded()`. Ele chama o método `sendMessage()` da classe `ContactFacade` e lhe passa os dados do formulário. E como obtemos o objeto `ContactFacade`? O construtor nos passará os dados:

```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');
	}
}
```

Após o envio do e-mail, mostramos ao usuário a chamada [mensagem flash |application:components#flash-messages], confirmando que a mensagem foi enviada, e então redirecionamos para a página seguinte para que o formulário não possa ser reapresentado usando *refresh* no navegador.


Bem, se tudo funcionar, você deve poder enviar um e-mail a partir de seu formulário de contato. Parabéns!


Modelo de e-mail HTML .[#toc-html-email-template]
-------------------------------------------------

Por enquanto, é enviado um e-mail com texto simples contendo apenas a mensagem enviada pelo formulário. Mas podemos usar HTML no e-mail e torná-lo mais atraente. Criaremos um modelo para ele em Latte, que salvaremos em `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 modificar `ContactFacade` para usar este modelo. No construtor, solicitamos a classe `LatteFactory`, que pode produzir o objeto `Latte\Engine`, um [renderizador de modelos Latte |latte:develop#how-to-render-a-template]. Usamos o método `renderToString()` para renderizar o modelo em um arquivo, o primeiro parâmetro é o caminho para o modelo e o segundo são as variáveis.

```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);
	}
}
```

Passamos então o e-mail HTML gerado para o método `setHtmlBody()` em vez do original `setBody()`. Também não precisamos especificar o assunto do e-mail em `setSubject()`, pois a biblioteca o retira do elemento `<title>` em modelo.


Configurando .[#toc-configuring]
--------------------------------

No código de classe `ContactFacade`, nosso e-mail administrativo `admin@example.com` ainda está codificado. Seria melhor movê-lo para o arquivo de configuração. Como fazer isso?

Primeiro, modificamos a classe `ContactFacade` e substituímos a string de e-mail por uma variável passada pelo construtor:

```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);
		// ...
	}
}
```

E o segundo passo é colocar o valor desta variável na configuração. No arquivo `app/config/services.neon`, adicionamos:

```neon
services:
	- App\Model\ContactFacade(adminEmail: admin@example.com)
```

E é isso aí. Se houver muitos itens na seção `services` e você sentir que o e-mail está se perdendo entre eles, podemos torná-lo uma variável. Modificaremos a entrada para:

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

E defina esta variável no arquivo `app/config/common.neon`:

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

E está feito!


{{sitename: Melhores Práticas}}

Vamos criar um formulário de contato

Vamos ver como criar um formulário de contato em Nette, inclusive enviando-o para um e-mail. Então, vamos fazer isso!

Primeiro temos que criar um novo projeto. Como explica a página Primeiros Pass os. E depois podemos começar a criar o formulário.

A maneira mais fácil é criar o formulário diretamente no Apresentador. Podemos usar o pré-fabricado HomePresenter. Acrescentaremos o componente contactForm que representa o formulário. Fazemos isso escrevendo o método de fábrica createComponentContactForm() no código que irá produzir o 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
	}
}

Como você pode ver, nós criamos dois métodos. O primeiro método createComponentContactForm() cria uma nova forma. Este tem campos para nome, e-mail e mensagem, que adicionamos usando os métodos addText(), addEmail() e addTextArea(). Também adicionamos um botão para enviar o formulário. Mas e se o usuário não preencher alguns campos? Nesse caso, devemos avisá-lo que se trata de um campo obrigatório. Fizemos isso com o método setRequired(). Finalmente, adicionamos também um evento onSuccess, que é acionado se o formulário for submetido com sucesso. Em nosso caso, ele chama o método contactFormSucceeded, que se encarrega de processar o formulário submetido. Acrescentaremos isso ao código em um momento.

Deixe o componente contantForm ser apresentado no modelo Home/default.latte:

{block content}
<h1>Contant Form</h1>
{control contactForm}

Para enviar o e-mail em si, criamos uma nova classe chamada ContactFacade e a colocamos no arquivo 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);
	}
}

O método sendMessage() irá criar e enviar o e-mail. Para isso, ele usa o chamado mailer, que passa como uma dependência através do construtor. Leia mais sobre o envio de e-mails.

Agora, vamos voltar ao apresentador e completar o método contactFormSucceeded(). Ele chama o método sendMessage() da classe ContactFacade e lhe passa os dados do formulário. E como obtemos o objeto ContactFacade? O construtor nos passará os dados:

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');
	}
}

Após o envio do e-mail, mostramos ao usuário a chamada mensagem flash, confirmando que a mensagem foi enviada, e então redirecionamos para a página seguinte para que o formulário não possa ser reapresentado usando refresh no navegador.

Bem, se tudo funcionar, você deve poder enviar um e-mail a partir de seu formulário de contato. Parabéns!

Modelo de e-mail HTML

Por enquanto, é enviado um e-mail com texto simples contendo apenas a mensagem enviada pelo formulário. Mas podemos usar HTML no e-mail e torná-lo mais atraente. Criaremos um modelo para ele em Latte, que salvaremos em 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 modificar ContactFacade para usar este modelo. No construtor, solicitamos a classe LatteFactory, que pode produzir o objeto Latte\Engine, um renderizador de modelos Latte. Usamos o método renderToString() para renderizar o modelo em um arquivo, o primeiro parâmetro é o caminho para o modelo e o segundo são as variáveis.

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);
	}
}

Passamos então o e-mail HTML gerado para o método setHtmlBody() em vez do original setBody(). Também não precisamos especificar o assunto do e-mail em setSubject(), pois a biblioteca o retira do elemento <title> em modelo.

Configurando

No código de classe ContactFacade, nosso e-mail administrativo admin@example.com ainda está codificado. Seria melhor movê-lo para o arquivo de configuração. Como fazer isso?

Primeiro, modificamos a classe ContactFacade e substituímos a string de e-mail por uma variável passada pelo construtor:

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 o segundo passo é colocar o valor desta variável na configuração. No arquivo app/config/services.neon, adicionamos:

services:
	- App\Model\ContactFacade(adminEmail: admin@example.com)

E é isso aí. Se houver muitos itens na seção services e você sentir que o e-mail está se perdendo entre eles, podemos torná-lo uma variável. Modificaremos a entrada para:

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

E defina esta variável no arquivo app/config/common.neon:

parameters:
	adminEmail: admin@example.com

E está feito!