Nette Documentation Preview

syntax
Egyetlen poszt oldal
********************

.[perex]
Adjunk hozzá egy másik oldalt a blogunkhoz, amely egy adott blogbejegyzés tartalmát jeleníti meg.


Létre kell hoznunk egy új renderelési metódust, amely egy adott blogbejegyzést fog lekérni és átadni a sablonhoz. Ha ez a nézet a `HomePresenter` oldalon van, az nem szép, mert egy blogbejegyzésről van szó, nem pedig a kezdőlapról. Tehát hozzunk létre egy új osztályt `PostPresenter` és helyezzük el a `app/UI/Post/`. Szüksége lesz egy adatbázis-kapcsolatra, ezért a *adatbázis injekció* kódot ismét oda tesszük.

A `PostPresenter` így kell kinéznie:

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

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

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

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

Be kell állítanunk egy megfelelő névteret `App\UI\Post` a prezenterünk számára. Ez a [prezenter leképezésétől |https://github.com/nette-examples/quickstart/blob/v4.0/config/common.neon#L6-L7] függ.

A `renderShow` módszer egy argumentumot igényel - a megjelenítendő poszt azonosítóját. Ezután betölti a bejegyzést az adatbázisból, és az eredményt átadja a sablonhoz.

A `Home/default.latte` sablonban a `Post:show` műveletre mutató linket adunk hozzá:

```latte .{file:app/UI/Home/default.latte}
...
<h2><a href="{link Post:show $post->id}">{$post->title}</a></h2>
...
```

A `{link}` címke URL-címet generál, amely a `Post:show` akcióra mutat. Ez a tag a bejegyzés azonosítóját is továbbítja argumentumként.


Ugyanezt röviden megírhatjuk az n:attribútum használatával:

```latte .{file:app/UI/Home/default.latte}
...
<h2><a n:href="Post:show $post->id">{$post->title}</a></h2>
...
```

A `n:href` attribútum hasonló a `{link}` címkéhez.



A `Post:show` művelet sablonja még nem létezik. Meg tudjuk nyitni a linket erre a bejegyzésre. [Tracy |tracy:] hibát fog mutatni, hogy miért nem létezik a `Post/show.latte`. Ha bármilyen más hibajelentést lát, akkor valószínűleg be kell kapcsolnia a mod_rewrite-et a webszerverén.

Tehát létrehozzuk a `Post/show.latte` címet ezzel a tartalommal:

```latte .{file:app/UI/Post/show.latte}
{block content}

<p><a n:href="Home:default">← back to posts list</a></p>

<div class="date">{$post->created_at|date:'F j, Y'}</div>

<h1 n:block="title">{$post->title}</h1>

<div class="post">{$post->content}</div>
```

Nézzük meg az egyes részeket.

Az első sor a korábban már látott "tartalom" nevű *nevesített blokk* definícióját kezdi. Ez egy *layout sablonban* fog megjelenni. Mint látható, hiányzik a `{/block}` végcímke. Ez opcionális.

A második sorban a blogbejegyzések listájára mutató visszahivatkozást adunk meg, így a felhasználó zökkenőmentesen tud előre-hátra navigálni a blogunkon. Ismét a `n:href` attribútumot használjuk, ezért a Nette gondoskodik az URL generálásáról helyettünk. A link a `Home` bemutató `default` műveletére mutat (írhatnánk `n:href="Home:"` is, mivel a `default` művelet elhagyható).

A harmadik sorban a publikációs időbélyeget formázzuk meg egy szűrővel, ahogy azt már tudjuk.

A negyedik sor a blogbejegyzés *címét* jeleníti meg, mint egy `<h1>` címként. Van egy rész, amit talán nem ismersz, ez pedig a `n:block="title"`. Ki tudja találni, hogy mit csinál? Ha figyelmesen olvastad az előző részeket, akkor említettük a `n: attributes` címet. Ez egy másik példa. Ez a következővel egyenértékű:

```latte
{block title}<h1>{$post->title}</h1>{/block}
```

Egyszerűen fogalmazva, *újra definiál* egy `title` nevű blokkot. A blokk a *layout template*-ben (`/app/UI/@layout.latte:11`) van definiálva, és az OOP felülbíráláshoz hasonlóan itt is felülírásra kerül. Ezért az oldal `<title>` a megjelenített bejegyzés címét fogja tartalmazni. Az oldal címét felülbíráltuk, és ehhez csak a `n:block="title"` kellett. Nagyszerű, nem?

A sablon ötödik és egyben utolsó sorában megjelenik a bejegyzés teljes tartalma.


A bejegyzés azonosítójának ellenőrzése .[#toc-checking-post-id]
===============================================================

Mi történik, ha valaki megváltoztatja az URL-t és beilleszti a `postId` címet, ami nem létezik? Egy szép "az oldal nem található" hibaüzenetet kell adnunk a felhasználónak. Frissítsük a renderelési metódust a `PostPresenter`:

```php .{file:app/UI/Post/PostPresenter.php}
public function renderShow(int $id): void
{
	$post = $this->database
		->table('posts')
		->get($id);
	if (!$post) {
		$this->error('Post not found');
	}

	$this->template->post = $post;
}
```

Ha a poszt nem található, a `$this->error(...)` meghívása egy 404-es oldalt fog megjeleníteni egy szép és érthető üzenettel. Vegyük figyelembe, hogy a fejlesztői környezetben (a laptopon) nem fogjuk látni a hibaoldalt. Ehelyett a Tracy a kivételt fogja megmutatni a teljes részletességgel, ami elég kényelmes a fejlesztéshez. Mindkét módot ellenőrizheted, csak változtasd meg a `setDebugMode` címre átadott értéket a `Bootstrap.php`.


Összefoglaló .[#toc-summary]
============================

Van egy adatbázisunk blogbejegyzésekkel és egy webes alkalmazásunk két nézettel - az első az összes legutóbbi bejegyzés összefoglalóját, a második pedig egy adott bejegyzést jelenít meg.

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

Egyetlen poszt oldal

Adjunk hozzá egy másik oldalt a blogunkhoz, amely egy adott blogbejegyzés tartalmát jeleníti meg.

Létre kell hoznunk egy új renderelési metódust, amely egy adott blogbejegyzést fog lekérni és átadni a sablonhoz. Ha ez a nézet a HomePresenter oldalon van, az nem szép, mert egy blogbejegyzésről van szó, nem pedig a kezdőlapról. Tehát hozzunk létre egy új osztályt PostPresenter és helyezzük el a app/UI/Post/. Szüksége lesz egy adatbázis-kapcsolatra, ezért a adatbázis injekció kódot ismét oda tesszük.

A PostPresenter így kell kinéznie:

<?php
namespace App\UI\Post;

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

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

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

Be kell állítanunk egy megfelelő névteret App\UI\Post a prezenterünk számára. Ez a prezenter leképezésétől függ.

A renderShow módszer egy argumentumot igényel – a megjelenítendő poszt azonosítóját. Ezután betölti a bejegyzést az adatbázisból, és az eredményt átadja a sablonhoz.

A Home/default.latte sablonban a Post:show műveletre mutató linket adunk hozzá:

...
<h2><a href="{link Post:show $post->id}">{$post->title}</a></h2>
...

A {link} címke URL-címet generál, amely a Post:show akcióra mutat. Ez a tag a bejegyzés azonosítóját is továbbítja argumentumként.

Ugyanezt röviden megírhatjuk az n:attribútum használatával:

...
<h2><a n:href="Post:show $post->id">{$post->title}</a></h2>
...

A n:href attribútum hasonló a {link} címkéhez.

A Post:show művelet sablonja még nem létezik. Meg tudjuk nyitni a linket erre a bejegyzésre. Tracy hibát fog mutatni, hogy miért nem létezik a Post/show.latte. Ha bármilyen más hibajelentést lát, akkor valószínűleg be kell kapcsolnia a mod_rewrite-et a webszerverén.

Tehát létrehozzuk a Post/show.latte címet ezzel a tartalommal:

{block content}

<p><a n:href="Home:default">← back to posts list</a></p>

<div class="date">{$post->created_at|date:'F j, Y'}</div>

<h1 n:block="title">{$post->title}</h1>

<div class="post">{$post->content}</div>

Nézzük meg az egyes részeket.

Az első sor a korábban már látott „tartalom“ nevű nevesített blokk definícióját kezdi. Ez egy layout sablonban fog megjelenni. Mint látható, hiányzik a {/block} végcímke. Ez opcionális.

A második sorban a blogbejegyzések listájára mutató visszahivatkozást adunk meg, így a felhasználó zökkenőmentesen tud előre-hátra navigálni a blogunkon. Ismét a n:href attribútumot használjuk, ezért a Nette gondoskodik az URL generálásáról helyettünk. A link a Home bemutató default műveletére mutat (írhatnánk n:href="Home:" is, mivel a default művelet elhagyható).

A harmadik sorban a publikációs időbélyeget formázzuk meg egy szűrővel, ahogy azt már tudjuk.

A negyedik sor a blogbejegyzés címét jeleníti meg, mint egy <h1> címként. Van egy rész, amit talán nem ismersz, ez pedig a n:block="title". Ki tudja találni, hogy mit csinál? Ha figyelmesen olvastad az előző részeket, akkor említettük a n: attributes címet. Ez egy másik példa. Ez a következővel egyenértékű:

{block title}<h1>{$post->title}</h1>{/block}

Egyszerűen fogalmazva, újra definiál egy title nevű blokkot. A blokk a layout template-ben (/app/UI/@layout.latte:11) van definiálva, és az OOP felülbíráláshoz hasonlóan itt is felülírásra kerül. Ezért az oldal <title> a megjelenített bejegyzés címét fogja tartalmazni. Az oldal címét felülbíráltuk, és ehhez csak a n:block="title" kellett. Nagyszerű, nem?

A sablon ötödik és egyben utolsó sorában megjelenik a bejegyzés teljes tartalma.

A bejegyzés azonosítójának ellenőrzése

Mi történik, ha valaki megváltoztatja az URL-t és beilleszti a postId címet, ami nem létezik? Egy szép „az oldal nem található“ hibaüzenetet kell adnunk a felhasználónak. Frissítsük a renderelési metódust a PostPresenter:

public function renderShow(int $id): void
{
	$post = $this->database
		->table('posts')
		->get($id);
	if (!$post) {
		$this->error('Post not found');
	}

	$this->template->post = $post;
}

Ha a poszt nem található, a $this->error(...) meghívása egy 404-es oldalt fog megjeleníteni egy szép és érthető üzenettel. Vegyük figyelembe, hogy a fejlesztői környezetben (a laptopon) nem fogjuk látni a hibaoldalt. Ehelyett a Tracy a kivételt fogja megmutatni a teljes részletességgel, ami elég kényelmes a fejlesztéshez. Mindkét módot ellenőrizheted, csak változtasd meg a setDebugMode címre átadott értéket a Bootstrap.php.

Összefoglaló

Van egy adatbázisunk blogbejegyzésekkel és egy webes alkalmazásunk két nézettel – az első az összes legutóbbi bejegyzés összefoglalóját, a második pedig egy adott bejegyzést jelenít meg.