Nette Documentation Preview

syntax
Да създадем формуляр за контакт
*******************************

.[perex]
Нека разгледаме как да създадем формуляр за контакт в Nette, включително изпращането му на имейл. Така че нека го направим!

Първо трябва да създадем нов проект. Както е обяснено в страницата " [Започване" |nette:installation]. А след това можем да започнем създаването на формуляра.

Най-лесният начин е да създадете [формуляра директно в Presenter |forms:in-presenter]. Можем да използваме предварително създадената страница `HomePresenter`. Ще добавим компонента `contactForm`, представляващ формата. Ще направим това, като напишем фабричния метод на `createComponentContactForm()` в кода, който ще създава компонента:

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

Както можете да видите, създадохме два метода. Първият метод `createComponentContactForm()` създава нова форма. Тя има полета за име, имейл и съобщение, които добавяме с помощта на методите `addText()`, `addEmail()` и `addTextArea()`. Добавихме и бутон за изпращане на формуляра.
Но какво ще стане, ако потребителят не попълни някои полета? В такъв случай трябва да го уведомим, че това е задължително поле. Направихме това с метода `setRequired()`.
Накрая добавихме и [събитие |nette:glossary#events] `onSuccess`, което се задейства, ако формулярът е изпратен успешно. В нашия случай то извиква метода `contactFormSucceeded`, който се грижи за обработката на изпратения формуляр. След малко ще добавим това към кода.

Нека компонентът `contantForm` бъде визуализиран в шаблона `Home/default.latte`:

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

За да изпратим самия имейл, създаваме нов клас, наречен `ContactFacade`, и го поставяме във файла `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);
	}
}
```

Методът `sendMessage()` ще създаде и изпрати имейла. За целта той използва така наречения mailer, който предава като зависимост чрез конструктора. Прочетете повече за [изпращането на имейли |mail:].

Сега ще се върнем към презентатора и ще завършим метода `contactFormSucceeded()`. Той извиква метода `sendMessage()` на класа `ContactFacade` и му предава данните от формуляра. А как ще получим обекта `ContactFacade`? Той ще ни бъде предаден от конструктора:

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

След като имейлът бъде изпратен, показваме на потребителя т.нар. [флаш съобщение |application:components#flash-messages], с което потвърждаваме, че съобщението е изпратено, и след това пренасочваме към следващата страница, така че формулярът да не може да бъде изпратен отново с помощта на *refresh* в браузъра.


Е, ако всичко е наред, би трябвало да можете да изпратите имейл от формуляра си за контакт. Поздравления!


HTML шаблон за електронна поща .[#toc-html-email-template]
----------------------------------------------------------

Засега се изпраща имейл с обикновен текст, съдържащ само съобщението, изпратено от формуляра. Но можем да използваме HTML в имейла и да го направим по-привлекателен. Ще създадем шаблон за него в Latte, който ще запазим в `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>
```

Остава да модифицираме `ContactFacade`, за да използваме този шаблон. В конструктора заявяваме класа `LatteFactory`, който може да създаде обекта `Latte\Engine`, [рендер на шаблона Latte |latte:develop#how-to-render-a-template]. Използваме метода `renderToString()`, за да визуализираме шаблона във файл, като първият параметър е пътят до шаблона, а вторият - променливите.

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

След това предаваме генерирания HTML имейл на метода `setHtmlBody()` вместо на оригиналния `setBody()`. Също така не е необходимо да посочваме темата на имейла в `setSubject()`, защото библиотеката я взема от елемента `<title>` в шаблона.


Конфигуриране на .[#toc-configuring]
------------------------------------

В кода на класа `ContactFacade` нашият имейл адрес на администратора `admin@example.com` все още е твърдо кодиран. По-добре би било да го преместите в конфигурационния файл. Как да го направим?

Първо, модифицираме класа `ContactFacade` и заменяме низът за имейл с променлива, предадена от конструктора:

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

Втората стъпка е да въведем стойността на тази променлива в конфигурацията. Във файла `app/config/services.neon` добавяме:

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

И това е всичко. Ако в раздела `services` има много елементи и ви се струва, че имейлът се губи сред тях, можем да го направим променлива. Ще променим записа на:

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

И ще дефинираме тази променлива във файла `app/config/common.neon`:

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

И готово!


{{sitename: Най-добри практики}}

Да създадем формуляр за контакт

Нека разгледаме как да създадем формуляр за контакт в Nette, включително изпращането му на имейл. Така че нека го направим!

Първо трябва да създадем нов проект. Както е обяснено в страницата " Започване". А след това можем да започнем създаването на формуляра.

Най-лесният начин е да създадете формуляра директно в Presenter. Можем да използваме предварително създадената страница HomePresenter. Ще добавим компонента contactForm, представляващ формата. Ще направим това, като напишем фабричния метод на createComponentContactForm() в кода, който ще създава компонента:

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

Както можете да видите, създадохме два метода. Първият метод createComponentContactForm() създава нова форма. Тя има полета за име, имейл и съобщение, които добавяме с помощта на методите addText(), addEmail() и addTextArea(). Добавихме и бутон за изпращане на формуляра. Но какво ще стане, ако потребителят не попълни някои полета? В такъв случай трябва да го уведомим, че това е задължително поле. Направихме това с метода setRequired(). Накрая добавихме и събитие onSuccess, което се задейства, ако формулярът е изпратен успешно. В нашия случай то извиква метода contactFormSucceeded, който се грижи за обработката на изпратения формуляр. След малко ще добавим това към кода.

Нека компонентът contantForm бъде визуализиран в шаблона Home/default.latte:

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

За да изпратим самия имейл, създаваме нов клас, наречен ContactFacade, и го поставяме във файла 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);
	}
}

Методът sendMessage() ще създаде и изпрати имейла. За целта той използва така наречения mailer, който предава като зависимост чрез конструктора. Прочетете повече за изпращането на имейли.

Сега ще се върнем към презентатора и ще завършим метода contactFormSucceeded(). Той извиква метода sendMessage() на класа ContactFacade и му предава данните от формуляра. А как ще получим обекта ContactFacade? Той ще ни бъде предаден от конструктора:

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

След като имейлът бъде изпратен, показваме на потребителя т.нар. флаш съобщение, с което потвърждаваме, че съобщението е изпратено, и след това пренасочваме към следващата страница, така че формулярът да не може да бъде изпратен отново с помощта на refresh в браузъра.

Е, ако всичко е наред, би трябвало да можете да изпратите имейл от формуляра си за контакт. Поздравления!

HTML шаблон за електронна поща

Засега се изпраща имейл с обикновен текст, съдържащ само съобщението, изпратено от формуляра. Но можем да използваме HTML в имейла и да го направим по-привлекателен. Ще създадем шаблон за него в Latte, който ще запазим в 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>

Остава да модифицираме ContactFacade, за да използваме този шаблон. В конструктора заявяваме класа LatteFactory, който може да създаде обекта Latte\Engine, рендер на шаблона Latte. Използваме метода renderToString(), за да визуализираме шаблона във файл, като първият параметър е пътят до шаблона, а вторият – променливите.

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

След това предаваме генерирания HTML имейл на метода setHtmlBody() вместо на оригиналния setBody(). Също така не е необходимо да посочваме темата на имейла в setSubject(), защото библиотеката я взема от елемента <title> в шаблона.

Конфигуриране на

В кода на класа ContactFacade нашият имейл адрес на администратора admin@example.com все още е твърдо кодиран. По-добре би било да го преместите в конфигурационния файл. Как да го направим?

Първо, модифицираме класа ContactFacade и заменяме низът за имейл с променлива, предадена от конструктора:

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

Втората стъпка е да въведем стойността на тази променлива в конфигурацията. Във файла app/config/services.neon добавяме:

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

И това е всичко. Ако в раздела services има много елементи и ви се струва, че имейлът се губи сред тях, можем да го направим променлива. Ще променим записа на:

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

И ще дефинираме тази променлива във файла app/config/common.neon:

parameters:
	adminEmail: admin@example.com

И готово!