Nette Documentation Preview

syntax
Ustvarimo kontaktni obrazec
***************************

.[perex]
Oglejmo si, kako ustvariti obrazec za stik v Nette, vključno s pošiljanjem v e-pošto. Naredimo to!

Najprej moramo ustvariti nov projekt. Kot je razloženo na strani [Začetek |nette:installation]. Nato pa lahko začnemo ustvarjati obrazec.

Najlažje je [obrazec |forms:in-presenter] ustvariti [neposredno v programu Presenter |forms:in-presenter]. Uporabimo lahko vnaprej pripravljene spletne strani `HomePresenter`. Dodali bomo komponento `contactForm`, ki predstavlja obrazec. To storimo tako, da v kodo, ki bo izdelala komponento, zapišemo tovarniško metodo `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
	}
}
```

Kot lahko vidite, smo ustvarili dve metodi. Prva metoda `createComponentContactForm()` ustvari nov obrazec. Ta ima polja za ime, e-pošto in sporočilo, ki jih dodamo z metodami `addText()`, `addEmail()` in `addTextArea()`. Dodali smo tudi gumb za pošiljanje obrazca.
Kaj pa, če uporabnik ne izpolni nekaterih polj? V tem primeru mu moramo sporočiti, da gre za zahtevano polje. To smo storili z metodo `setRequired()`.
Na koncu smo dodali še [dogodek |nette:glossary#events] `onSuccess`, ki se sproži, če je obrazec uspešno oddan. V našem primeru pokliče metodo `contactFormSucceeded`, ki poskrbi za obdelavo oddanega obrazca. To bomo v kodo dodali v naslednjem trenutku.

Naj bo komponenta `contantForm` prikazana v predlogi `Home/default.latte`:

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

Za pošiljanje samega elektronskega sporočila ustvarimo nov razred z imenom `ContactFacade` in ga postavimo v datoteko `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);
	}
}
```

Metoda `sendMessage()` bo ustvarila in poslala elektronsko sporočilo. Za to uporablja tako imenovani mailer, ki ga prek konstruktorja posreduje kot odvisnost. Preberite več o [pošiljanju e-pošte |mail:].

Zdaj se bomo vrnili k predstavniku in dokončali metodo `contactFormSucceeded()`. Pokliče metodo `sendMessage()` razreda `ContactFacade` in mu posreduje podatke iz obrazca. In kako dobimo objekt `ContactFacade`? Predal nam ga bo konstruktor:

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

Ko je elektronsko sporočilo poslano, uporabniku prikažemo tako imenovano [sporočilo flash |application:components#flash-messages], ki potrjuje, da je bilo sporočilo poslano, nato pa ga preusmerimo na naslednjo stran, tako da obrazca ni mogoče ponovno poslati z uporabo *refresh* v brskalniku.


Če vse deluje, bi morali biti sposobni poslati elektronsko sporočilo iz kontaktnega obrazca. Čestitamo!


Predloga e-pošte HTML .[#toc-html-email-template]
-------------------------------------------------

Za zdaj je poslano navadno besedilno e-poštno sporočilo, ki vsebuje samo sporočilo, poslano z obrazcem. Vendar lahko v e-poštnem sporočilu uporabimo HTML in ga naredimo privlačnejšega. Za to bomo v Latte ustvarili predlogo, ki jo bomo shranili v `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>
```

Za uporabo te predloge je treba spremeniti spletno mesto `ContactFacade`. V konstruktorju zahtevamo razred `LatteFactory`, ki lahko ustvari objekt `Latte\Engine`, [upodobljevalnik predloge Latte |latte:develop#how-to-render-a-template]. Uporabimo metodo `renderToString()` za upodabljanje predloge v datoteko, pri čemer je prvi parameter pot do predloge, drugi pa spremenljivke.

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

Ustvarjeno elektronsko sporočilo HTML nato posredujemo metodi `setHtmlBody()` namesto prvotnega `setBody()`. Prav tako nam ni treba določiti predmeta e-pošte v `setSubject()`, saj ga knjižnica prevzame iz elementa `<title>` v predlogi.


Konfiguracija .[#toc-configuring]
---------------------------------

V kodi razreda `ContactFacade` je še vedno trdno zakodirano naše upraviteljevo e-poštno sporočilo `admin@example.com`. Bolje bi bilo, če bi ga prenesli v konfiguracijsko datoteko. Kako to storiti?

Najprej spremenimo razred `ContactFacade` in niz elektronske pošte nadomestimo s spremenljivko, ki jo posreduje konstruktor:

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

Drugi korak je, da vrednost te spremenljivke vnesemo v konfiguracijo. V datoteko `app/config/services.neon` dodamo:

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

In to je to. Če je v razdelku `services` veliko elementov in se vam zdi, da se elektronsko sporočilo izgublja med njimi, ga lahko naredimo za spremenljivko. Vnos bomo spremenili v:

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

in to spremenljivko opredelimo v datoteki `app/config/common.neon`:

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

In končano je!


{{sitename: Best Practices}}

Ustvarimo kontaktni obrazec

Oglejmo si, kako ustvariti obrazec za stik v Nette, vključno s pošiljanjem v e-pošto. Naredimo to!

Najprej moramo ustvariti nov projekt. Kot je razloženo na strani Začetek. Nato pa lahko začnemo ustvarjati obrazec.

Najlažje je obrazec ustvariti neposredno v programu Presenter. Uporabimo lahko vnaprej pripravljene spletne strani HomePresenter. Dodali bomo komponento contactForm, ki predstavlja obrazec. To storimo tako, da v kodo, ki bo izdelala komponento, zapišemo tovarniško metodo 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
	}
}

Kot lahko vidite, smo ustvarili dve metodi. Prva metoda createComponentContactForm() ustvari nov obrazec. Ta ima polja za ime, e-pošto in sporočilo, ki jih dodamo z metodami addText(), addEmail() in addTextArea(). Dodali smo tudi gumb za pošiljanje obrazca. Kaj pa, če uporabnik ne izpolni nekaterih polj? V tem primeru mu moramo sporočiti, da gre za zahtevano polje. To smo storili z metodo setRequired(). Na koncu smo dodali še dogodek onSuccess, ki se sproži, če je obrazec uspešno oddan. V našem primeru pokliče metodo contactFormSucceeded, ki poskrbi za obdelavo oddanega obrazca. To bomo v kodo dodali v naslednjem trenutku.

Naj bo komponenta contantForm prikazana v predlogi Home/default.latte:

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

Za pošiljanje samega elektronskega sporočila ustvarimo nov razred z imenom ContactFacade in ga postavimo v datoteko 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);
	}
}

Metoda sendMessage() bo ustvarila in poslala elektronsko sporočilo. Za to uporablja tako imenovani mailer, ki ga prek konstruktorja posreduje kot odvisnost. Preberite več o pošiljanju e-pošte.

Zdaj se bomo vrnili k predstavniku in dokončali metodo contactFormSucceeded(). Pokliče metodo sendMessage() razreda ContactFacade in mu posreduje podatke iz obrazca. In kako dobimo objekt ContactFacade? Predal nam ga bo konstruktor:

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

Ko je elektronsko sporočilo poslano, uporabniku prikažemo tako imenovano sporočilo flash, ki potrjuje, da je bilo sporočilo poslano, nato pa ga preusmerimo na naslednjo stran, tako da obrazca ni mogoče ponovno poslati z uporabo refresh v brskalniku.

Če vse deluje, bi morali biti sposobni poslati elektronsko sporočilo iz kontaktnega obrazca. Čestitamo!

Predloga e-pošte HTML

Za zdaj je poslano navadno besedilno e-poštno sporočilo, ki vsebuje samo sporočilo, poslano z obrazcem. Vendar lahko v e-poštnem sporočilu uporabimo HTML in ga naredimo privlačnejšega. Za to bomo v Latte ustvarili predlogo, ki jo bomo shranili v 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>

Za uporabo te predloge je treba spremeniti spletno mesto ContactFacade. V konstruktorju zahtevamo razred LatteFactory, ki lahko ustvari objekt Latte\Engine, upodobljevalnik predloge Latte. Uporabimo metodo renderToString() za upodabljanje predloge v datoteko, pri čemer je prvi parameter pot do predloge, drugi pa spremenljivke.

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

Ustvarjeno elektronsko sporočilo HTML nato posredujemo metodi setHtmlBody() namesto prvotnega setBody(). Prav tako nam ni treba določiti predmeta e-pošte v setSubject(), saj ga knjižnica prevzame iz elementa <title> v predlogi.

Konfiguracija

V kodi razreda ContactFacade je še vedno trdno zakodirano naše upraviteljevo e-poštno sporočilo admin@example.com. Bolje bi bilo, če bi ga prenesli v konfiguracijsko datoteko. Kako to storiti?

Najprej spremenimo razred ContactFacade in niz elektronske pošte nadomestimo s spremenljivko, ki jo posreduje konstruktor:

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

Drugi korak je, da vrednost te spremenljivke vnesemo v konfiguracijo. V datoteko app/config/services.neon dodamo:

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

In to je to. Če je v razdelku services veliko elementov in se vam zdi, da se elektronsko sporočilo izgublja med njimi, ga lahko naredimo za spremenljivko. Vnos bomo spremenili v:

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

in to spremenljivko opredelimo v datoteki app/config/common.neon:

parameters:
	adminEmail: admin@example.com

In končano je!