Nette Documentation Preview

syntax
Stran z eno objavo
******************

.[perex]
Dodajmo še eno stran na naš blog, ki bo prikazovala vsebino ene posamezne objave.


Ustvariti moramo novo metodo izrisa, ki bo pobrala eno določeno objavo na blogu in jo posredovala predlogi. Imeti ta pogled v naslovu `HomePresenter` ni lepo, saj gre za blogovsko objavo in ne za domačo stran. Zato ustvarimo nov razred `PostPresenter` in ga postavimo v `app/UI/Post/`. Potreboval bo povezavo s podatkovno bazo, zato tja ponovno postavimo kodo *database injection*.

Razred `PostPresenter` naj bo videti takole:

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

Nastaviti moramo pravilen imenski prostor `App\UI\Post` za našega predstavnika. To je odvisno od [preslikave predstavnika |https://github.com/nette-examples/quickstart/blob/v4.0/config/common.neon#L6-L7].

Metoda `renderShow` zahteva en argument - ID prispevka, ki ga je treba prikazati. Nato objavo naloži iz podatkovne zbirke in rezultat posreduje predlogi.

V predlogi `Home/default.latte` dodamo povezavo do akcije `Post:show`:

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

Oznaka `{link}` ustvari naslov URL, ki kaže na akcijo `Post:show`. Ta oznaka kot argument posreduje tudi ID objave.


Enako lahko na kratko zapišemo z uporabo atributa n:attribute:

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

Atribut `n:href` je podoben oznaki `{link}`.



Predloga za akcijo `Post:show` še ne obstaja. Odpremo lahko povezavo do tega prispevka. [Tracy |tracy:] bo prikazal napako, zakaj `Post/show.latte` ne obstaja. Če se prikaže katero koli drugo poročilo o napaki, morate v spletnem strežniku verjetno vklopiti mod_rewrite.

Tako bomo ustvarili spletno stran `Post/show.latte` s to vsebino:

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

Oglejmo si posamezne dele.

V prvi vrstici se začne opredelitev *poimenovanega bloka* z imenom "content", ki smo ga videli prej. Prikazan bo v *šabloni za postavitev*. Kot lahko vidite, manjka končna oznaka `{/block}`. Ta je neobvezna.

Druga vrstica zagotavlja povratno povezavo na seznam blogovskih objav, tako da se lahko uporabnik nemoteno pomika naprej in nazaj po našem blogu. Ponovno uporabimo atribut `n:href`, zato bo Nette poskrbel za generiranje naslova URL namesto nas. Povezava kaže na akcijo `default` predstavnika `Home` (lahko zapišete tudi `n:href="Home:"`, saj lahko akcijo `default` izpustite).

Tretja vrstica oblikuje časovni žig objave s filtrom, kot že vemo.

Četrta vrstica prikaže *naslov* prispevka na blogu kot `<h1>` naslov. Obstaja del, ki vam morda ni znan, in sicer `n:block="title"`. Ali lahko uganete, kaj počne? Če ste pozorno prebrali prejšnje dele, smo omenili `n: attributes`. To je še en primer. Enakovreden je:

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

Preprosto povedano, *na novo definira* blok z imenom `title`. Blok je opredeljen v *šabloni za postavitev* (`/app/UI/@layout.latte:11`) in tako kot pri OOP overriding, je tudi tukaj prepisan. Zato se na strani `<title>` bo vsebovala naslov prikazane objave. Prekrili smo naslov strani in vse, kar smo potrebovali, je bilo `n:block="title"`. Super, kajne?

V peti in zadnji vrstici predloge je prikazana celotna vsebina vašega prispevka.


Preverjanje ID objave .[#toc-checking-post-id]
==============================================

Kaj se zgodi, če nekdo spremeni naslov URL in vstavi `postId`, ki ne obstaja? Uporabniku moramo zagotoviti lepo napako "stran ni bila najdena". Posodobimo metodo upodabljanja v `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;
}
```

Če objave ni mogoče najti, bo klic `$this->error(...)` prikazal stran 404 z lepim in razumljivim sporočilom. Upoštevajte, da v razvojnem okolju (na prenosnem računalniku) ne boste videli strani z napako. Namesto tega bo Tracy prikazal izjemo z vsemi podrobnostmi, kar je precej priročno za razvoj. Preverite lahko oba načina, samo spremenite vrednost, ki jo posredujete `setDebugMode` v `Bootstrap.php`.


Povzetek .[#toc-summary]
========================

Imamo podatkovno zbirko z objavami na blogu in spletno aplikacijo z dvema pogledoma - prvi prikazuje povzetek vseh zadnjih objav, drugi pa eno določeno objavo.

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

Stran z eno objavo

Dodajmo še eno stran na naš blog, ki bo prikazovala vsebino ene posamezne objave.

Ustvariti moramo novo metodo izrisa, ki bo pobrala eno določeno objavo na blogu in jo posredovala predlogi. Imeti ta pogled v naslovu HomePresenter ni lepo, saj gre za blogovsko objavo in ne za domačo stran. Zato ustvarimo nov razred PostPresenter in ga postavimo v app/UI/Post/. Potreboval bo povezavo s podatkovno bazo, zato tja ponovno postavimo kodo database injection.

Razred PostPresenter naj bo videti takole:

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

Nastaviti moramo pravilen imenski prostor App\UI\Post za našega predstavnika. To je odvisno od preslikave predstavnika.

Metoda renderShow zahteva en argument – ID prispevka, ki ga je treba prikazati. Nato objavo naloži iz podatkovne zbirke in rezultat posreduje predlogi.

V predlogi Home/default.latte dodamo povezavo do akcije Post:show:

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

Oznaka {link} ustvari naslov URL, ki kaže na akcijo Post:show. Ta oznaka kot argument posreduje tudi ID objave.

Enako lahko na kratko zapišemo z uporabo atributa n:attribute:

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

Atribut n:href je podoben oznaki {link}.

Predloga za akcijo Post:show še ne obstaja. Odpremo lahko povezavo do tega prispevka. Tracy bo prikazal napako, zakaj Post/show.latte ne obstaja. Če se prikaže katero koli drugo poročilo o napaki, morate v spletnem strežniku verjetno vklopiti mod_rewrite.

Tako bomo ustvarili spletno stran Post/show.latte s to vsebino:

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

Oglejmo si posamezne dele.

V prvi vrstici se začne opredelitev poimenovanega bloka z imenom „content“, ki smo ga videli prej. Prikazan bo v šabloni za postavitev. Kot lahko vidite, manjka končna oznaka {/block}. Ta je neobvezna.

Druga vrstica zagotavlja povratno povezavo na seznam blogovskih objav, tako da se lahko uporabnik nemoteno pomika naprej in nazaj po našem blogu. Ponovno uporabimo atribut n:href, zato bo Nette poskrbel za generiranje naslova URL namesto nas. Povezava kaže na akcijo default predstavnika Home (lahko zapišete tudi n:href="Home:", saj lahko akcijo default izpustite).

Tretja vrstica oblikuje časovni žig objave s filtrom, kot že vemo.

Četrta vrstica prikaže naslov prispevka na blogu kot <h1> naslov. Obstaja del, ki vam morda ni znan, in sicer n:block="title". Ali lahko uganete, kaj počne? Če ste pozorno prebrali prejšnje dele, smo omenili n: attributes. To je še en primer. Enakovreden je:

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

Preprosto povedano, na novo definira blok z imenom title. Blok je opredeljen v šabloni za postavitev (/app/UI/@layout.latte:11) in tako kot pri OOP overriding, je tudi tukaj prepisan. Zato se na strani <title> bo vsebovala naslov prikazane objave. Prekrili smo naslov strani in vse, kar smo potrebovali, je bilo n:block="title". Super, kajne?

V peti in zadnji vrstici predloge je prikazana celotna vsebina vašega prispevka.

Preverjanje ID objave

Kaj se zgodi, če nekdo spremeni naslov URL in vstavi postId, ki ne obstaja? Uporabniku moramo zagotoviti lepo napako „stran ni bila najdena“. Posodobimo metodo upodabljanja v 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;
}

Če objave ni mogoče najti, bo klic $this->error(...) prikazal stran 404 z lepim in razumljivim sporočilom. Upoštevajte, da v razvojnem okolju (na prenosnem računalniku) ne boste videli strani z napako. Namesto tega bo Tracy prikazal izjemo z vsemi podrobnostmi, kar je precej priročno za razvoj. Preverite lahko oba načina, samo spremenite vrednost, ki jo posredujete setDebugMode v Bootstrap.php.

Povzetek

Imamo podatkovno zbirko z objavami na blogu in spletno aplikacijo z dvema pogledoma – prvi prikazuje povzetek vseh zadnjih objav, drugi pa eno določeno objavo.