Nette Documentation Preview

syntax
Vytváření a editování příspěvků
*******************************

To je paráda! Máme super cool nový blog, lidé urputně diskutují v komentářích a my máme konečně trochu času na další programování. Přestože je Adminer skvělý nástroj, není úplně ideální pro psaní nových příspěvků na blog. Zřejmě je ten správný čas pro vytvoření jednoduchého formuláře pro přidání nových příspěvků přímo z aplikace. Pojďme na to.

Začněme s navržením uživatelského rozhraní:

1. Na úvodní stránce přidáme odkaz "Napsat nový příspěvek".
2. Tento odkaz zobrazí formulář s titulkem a textareou pro obsah příspěvku.
3. Když klikneme na tlačítko Uložit, příspěvek se uloží do databáze.

Později také přidáme přihlašování a přidávání příspěvků umožníme pouze přihlášeným uživatelům. Ale to až později. Jaký kód potřebujeme napsat teď, aby vše fungovalo?

1. Vytvoříme nový presenter s formulářem pro přidávání příspěvků.
2. Definujeme callback, který se spustí po úspěšném odeslání formuláře a který nový příspěvek uloží do databáze.
3. Vytvoříme novou šablonu na které bude onen formulář.
4. Přidáme odkaz na formulář do šablony hlavní stránky.


Nový presenter
==============

Nový presenter nazveme `EditPresenter` a uložíme do `app/UI/Edit/`. Také se potřebuje připojit k databázi, takže zde opět napíšeme konstruktor, který bude vyžadovat databázové připojení:

```php .{file:app/UI/Edit/EditPresenter.php}
<?php
namespace App\UI\Edit;

use Nette;
use Nette\Application\UI\Form;

final class EditPresenter extends Nette\Application\UI\Presenter
{
	public function __construct(
		private Nette\Database\Explorer $database,
	) {
	}
}
```


Formulář pro ukládání příspěvků
===============================

Formuláře a komponenty jsme si již vysvětlili při vytváření komentářů. Pokud to stále není jasné, jděte si projít [tvorbu formulářů a komponent |comments#formular-pro-komentovani], my zde zatím počkáme ;)

Nyní přidejme tuto metodu do presenteru `EditPresenter`:

```php .{file:app/UI/Edit/EditPresenter.php}
protected function createComponentPostForm(): Form
{
	$form = new Form;
	$form->addText('title', 'Titulek:')
		->setRequired();
	$form->addTextArea('content', 'Obsah:')
		->setRequired();

	$form->addSubmit('send', 'Uložit a publikovat');
	$form->onSuccess[] = $this->postFormSucceeded(...);

	return $form;
}
```


Ukládání nového příspěvku z formuláře
=====================================

Pokračujeme přidáním metody, která zpracuje data z formuláře:

```php .{file:app/UI/Edit/EditPresenter.php}
private function postFormSucceeded(array $data): void
{
	$post = $this->database
		->table('posts')
		->insert($data);

	$this->flashMessage("Příspěvek byl úspěšně publikován.", 'success');
	$this->redirect('Post:show', $post->id);
}
```

Pouze rychlá rekapitulace: tato metoda získá data z formuláře, vloží je do databáze, vytvoří zprávu pro uživatele o úspěšném uložení příspěvku a přesměruje na stránku s novým příspěvkem, takže hned uvidíme, jak vypadá.


Stránka pro vytvoření nového příspěvku
======================================

Vytvořme nyní šablonu `Edit/create.latte`:

```latte .{file:app/UI/Edit/create.latte}
{block content}
<h1>Nový příspěvek</h1>

{control postForm}
```

Vše by již mělo být jasné. Poslední řádka vykresluje formulář, který teprve vytvoříme.

Mohli bychom vytvořit také odpovídající metodu `renderCreate`, ale ono není nutné. Nepotřebujeme získávat žádná data z databáze a předávat je do šablony, takže by ta metoda byla prázdná. V takovýchto případech nemusí metoda vůbec existovat.


Odkaz na vytváření příspěvků
============================

Pravděpodobně již víte jak přidat odkaz na `EditPresenter` a jeho akci `create`. Vyzkoušejte si to.

Stačí do souboru `app/UI/Home/default.latte` přidat:

```latte
<a n:href="Edit:create">Napsat nový příspěvek</a>
```


Úprava příspěvků
================

Nyní přidáme také možnost editace příspěvku. Bude to velmi jednoduché. Již máme hotový formulář `postForm` a můžeme jej použít i pro editaci.

Přidáme novou stránku `edit` do presenteru `EditPresenter`:

```php .{file:app/UI/Edit/EditPresenter.php}
public function renderEdit(int $id): void
{
	$post = $this->database
		->table('posts')
		->get($id);

	if (!$post) {
		$this->error('Post not found');
	}

	$this->getComponent('postForm')
		->setDefaults($post->toArray());
}
```

A vytvoříme další šablonu `Edit/edit.latte`:

```latte .{file:app/UI/Edit/edit.latte}
{block content}
<h1>Upravit příspěvek</h1>

{control postForm}
```

A upravíme metodu `postFormSucceeded`, která bude schopna jednak přidat nový článek (tak jako to dělá teď) a také již existující článek editovat:

```php .{file:app/UI/Edit/EditPresenter.php}
private function postFormSucceeded(array $data): void
{
	$id = $this->getParameter('id');

	if ($id) {
		$post = $this->database
			->table('posts')
			->get($id);
		$post->update($data);

	} else {
		$post = $this->database
			->table('posts')
			->insert($data);
	}

	$this->flashMessage('Příspěvek byl úspěšně publikován.', 'success');
	$this->redirect('Post:show', $post->id);
}
```

Pokud je k dispozici parametr `id`, znamená to, že budeme upravovat příspěvek. V tom případě ověříme, že požadovaný příspěvek opravdu existuje a pokud ano, aktualizujeme jej v databázi. Pokud parametr `id` není k dispozici, pak to znamená, že by měl být nový příspěvek přidán.

Kde se však onen parametr `id` vezme? Jedná se o parametr, který byl vložen do metody `renderEdit`.

Nyní můžeme přidat odkaz do šablony `app/UI/Post/show.latte`:

```latte
<a n:href="Edit:edit $post->id">Upravit příspěvek</a>
```


Shrnutí
=======

Blog je nyní funkční, návštěvníci jej aktivně komentují a my již nepotřebujeme na publikaci Adminer. Aplikace je plně nezávislá a kdokoliv může přidat nový příspěvek. Tak moment, to asi není úplně v pořádku, že kdokoliv - a tím myslím opravdu kdokoliv s přístupem na internet - může přidávat nové příspěvky. Je zapotřebí nějaké zabezpečení, aby mohl nový příspěvek přidat pouze přihlášený uživatel. Na to se podíváme v příští kapitole.

{{priority: -1}}
{{sitename: Nette Quickstart}}

Vytváření a editování příspěvků

To je paráda! Máme super cool nový blog, lidé urputně diskutují v komentářích a my máme konečně trochu času na další programování. Přestože je Adminer skvělý nástroj, není úplně ideální pro psaní nových příspěvků na blog. Zřejmě je ten správný čas pro vytvoření jednoduchého formuláře pro přidání nových příspěvků přímo z aplikace. Pojďme na to.

Začněme s navržením uživatelského rozhraní:

  1. Na úvodní stránce přidáme odkaz „Napsat nový příspěvek“.
  2. Tento odkaz zobrazí formulář s titulkem a textareou pro obsah příspěvku.
  3. Když klikneme na tlačítko Uložit, příspěvek se uloží do databáze.

Později také přidáme přihlašování a přidávání příspěvků umožníme pouze přihlášeným uživatelům. Ale to až později. Jaký kód potřebujeme napsat teď, aby vše fungovalo?

  1. Vytvoříme nový presenter s formulářem pro přidávání příspěvků.
  2. Definujeme callback, který se spustí po úspěšném odeslání formuláře a který nový příspěvek uloží do databáze.
  3. Vytvoříme novou šablonu na které bude onen formulář.
  4. Přidáme odkaz na formulář do šablony hlavní stránky.

Nový presenter

Nový presenter nazveme EditPresenter a uložíme do app/UI/Edit/. Také se potřebuje připojit k databázi, takže zde opět napíšeme konstruktor, který bude vyžadovat databázové připojení:

<?php
namespace App\UI\Edit;

use Nette;
use Nette\Application\UI\Form;

final class EditPresenter extends Nette\Application\UI\Presenter
{
	public function __construct(
		private Nette\Database\Explorer $database,
	) {
	}
}

Formulář pro ukládání příspěvků

Formuláře a komponenty jsme si již vysvětlili při vytváření komentářů. Pokud to stále není jasné, jděte si projít tvorbu formulářů a komponent, my zde zatím počkáme ;)

Nyní přidejme tuto metodu do presenteru EditPresenter:

protected function createComponentPostForm(): Form
{
	$form = new Form;
	$form->addText('title', 'Titulek:')
		->setRequired();
	$form->addTextArea('content', 'Obsah:')
		->setRequired();

	$form->addSubmit('send', 'Uložit a publikovat');
	$form->onSuccess[] = $this->postFormSucceeded(...);

	return $form;
}

Ukládání nového příspěvku z formuláře

Pokračujeme přidáním metody, která zpracuje data z formuláře:

private function postFormSucceeded(array $data): void
{
	$post = $this->database
		->table('posts')
		->insert($data);

	$this->flashMessage("Příspěvek byl úspěšně publikován.", 'success');
	$this->redirect('Post:show', $post->id);
}

Pouze rychlá rekapitulace: tato metoda získá data z formuláře, vloží je do databáze, vytvoří zprávu pro uživatele o úspěšném uložení příspěvku a přesměruje na stránku s novým příspěvkem, takže hned uvidíme, jak vypadá.

Stránka pro vytvoření nového příspěvku

Vytvořme nyní šablonu Edit/create.latte:

{block content}
<h1>Nový příspěvek</h1>

{control postForm}

Vše by již mělo být jasné. Poslední řádka vykresluje formulář, který teprve vytvoříme.

Mohli bychom vytvořit také odpovídající metodu renderCreate, ale ono není nutné. Nepotřebujeme získávat žádná data z databáze a předávat je do šablony, takže by ta metoda byla prázdná. V takovýchto případech nemusí metoda vůbec existovat.

Odkaz na vytváření příspěvků

Pravděpodobně již víte jak přidat odkaz na EditPresenter a jeho akci create. Vyzkoušejte si to.

Stačí do souboru app/UI/Home/default.latte přidat:

<a n:href="Edit:create">Napsat nový příspěvek</a>

Úprava příspěvků

Nyní přidáme také možnost editace příspěvku. Bude to velmi jednoduché. Již máme hotový formulář postForm a můžeme jej použít i pro editaci.

Přidáme novou stránku edit do presenteru EditPresenter:

public function renderEdit(int $id): void
{
	$post = $this->database
		->table('posts')
		->get($id);

	if (!$post) {
		$this->error('Post not found');
	}

	$this->getComponent('postForm')
		->setDefaults($post->toArray());
}

A vytvoříme další šablonu Edit/edit.latte:

{block content}
<h1>Upravit příspěvek</h1>

{control postForm}

A upravíme metodu postFormSucceeded, která bude schopna jednak přidat nový článek (tak jako to dělá teď) a také již existující článek editovat:

private function postFormSucceeded(array $data): void
{
	$id = $this->getParameter('id');

	if ($id) {
		$post = $this->database
			->table('posts')
			->get($id);
		$post->update($data);

	} else {
		$post = $this->database
			->table('posts')
			->insert($data);
	}

	$this->flashMessage('Příspěvek byl úspěšně publikován.', 'success');
	$this->redirect('Post:show', $post->id);
}

Pokud je k dispozici parametr id, znamená to, že budeme upravovat příspěvek. V tom případě ověříme, že požadovaný příspěvek opravdu existuje a pokud ano, aktualizujeme jej v databázi. Pokud parametr id není k dispozici, pak to znamená, že by měl být nový příspěvek přidán.

Kde se však onen parametr id vezme? Jedná se o parametr, který byl vložen do metody renderEdit.

Nyní můžeme přidat odkaz do šablony app/UI/Post/show.latte:

<a n:href="Edit:edit $post->id">Upravit příspěvek</a>

Shrnutí

Blog je nyní funkční, návštěvníci jej aktivně komentují a my již nepotřebujeme na publikaci Adminer. Aplikace je plně nezávislá a kdokoliv může přidat nový příspěvek. Tak moment, to asi není úplně v pořádku, že kdokoliv – a tím myslím opravdu kdokoliv s přístupem na internet – může přidávat nové příspěvky. Je zapotřebí nějaké zabezpečení, aby mohl nový příspěvek přidat pouze přihlášený uživatel. Na to se podíváme v příští kapitole.