Nette Documentation Preview

syntax
Страница за индивидуално вписване
*********************************

.[perex]
Нека да добавим още една страница към нашия блог, за да покажем съдържанието на един конкретен запис в блога.


Трябва да създадем нов метод за визуализация, който да вземе един конкретен запис в блога и да го предаде на шаблона. Това визуализиране в `HomePresenter` не е много приятно, защото става дума за запис в блог, а не за начална страница. Така че нека създадем нов клас `PostPresenter` и да го поставим в `app/UI/Post/`. Тя ще се нуждае от връзка с база данни, така че поставете отново кода за инжектиране на зависимости* там.

`PostPresenter` трябва да изглежда по следния начин:

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

Трябва да зададем правилното пространство от имена `App\UI\Post` за нашия презентатор. Това зависи от [картографирането на водещия |https://github.com/nette-examples/quickstart/blob/v4.0/config/common.neon#L6-L7].

Методът `renderShow` изисква един аргумент - ID на публикацията на водещия. След това той зарежда тази публикация от базата данни и предава резултата на шаблона.

В шаблона `Home/default.latte` добавяме връзка към действието `Post:show`:

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

Тагът `{link}` генерира URL адрес, който насочва към действието `Post:show`. Този таг също така предава идентификатора на публикацията като аргумент.


Можем да напишем същото накратко, като използваме n:attribute:

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

Атрибутът `n:href` е подобен на тага `{link}`.



Шаблонът за действието `Post:show` все още не съществува. Можем да отворим връзка към тази публикация. [Tracy |tracy:] ще покаже грешка, че `app/UI/Post/show.latte` не съществува. Ако видите друг отчет за грешка, вероятно трябва да активирате mod_rewrite на уеб сървъра си.

Затова ще създадем `Post/show.latte` с това съдържание:

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

<p><a n:href="Home:default">← вернуться к списку постов</a></p>

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

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

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

Обмислете някои точки.

Първият ред започва дефиницията на *именния блок*, наречен `content`, който видяхме по-рано. Той ще се появи в шаблона на *разположението*.

Вторият ред съдържа обратна връзка към списъка с публикации в блога, така че потребителят да може да навигира плавно напред-назад из нашия блог. Отново използваме атрибута `n:href`, така че Nette ще се погрижи да генерира URL адреса вместо нас. Връзката сочи към действието `default` на водещия `Home` (може да напишете просто `n:href="Home:"`, тъй като действието `default` може да бъде пропуснато).

Третият ред форматира времевия печат на публикацията, като използва филтъра `date`, както вече знаем.

Четвъртият ред показва *заглавието* на записа в блога като заглавие `<h1>`. Има една част, която може би не познавате, а именно `n:block="title"`. Можете ли да познаете какво прави? Ако сте прочели внимателно предишните части, споменахме `n: атрибуты`. Ето още един пример. Това е равносилно на:

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

Просто казано, той *заменя* блок, наречен `title`. Блокът е дефиниран в *шаблона за оформление* (`/app/UI/@layout.latte:11`) и, както в случая на пренаписване на ООП, се пренаписва тук. Следователно `<title>` страници ще съдържа заглавието на показаната публикация. Премахнахме заглавието на страницата и всичко, от което се нуждаехме, беше `n:block="title"`. Чудесно, нали?

Петият и последен ред на шаблона показва пълното съдържание на публикацията ви.


Проверка на ID на публикацията .[#toc-checking-post-id]
=======================================================

Какво ще стане, ако някой промени URL адреса и вмъкне несъществуващ `postId`? Трябва да предоставим на потребителя хубава страница за грешка "Страницата не е намерена". Нека да актуализираме метода `render` във файла `PostPresenter.php`:

```php .{file:app/UI/Post/PostPresenter.php}
public function renderShow(int $id): void
{
	$post = $this->database
		->table('posts')
		->get($id);
	if (!$post) {
		$this->error('Страница не найдена!');
	}

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

Ако публикацията не може да бъде намерена, при извикване на `$this->error(...)` ще се покаже страница 404 с хубаво и ясно съобщение. Обърнете внимание, че в режим на разработка няма да видите страницата за грешки. Вместо това Трейси ще покаже изключение с пълна информация, което е доста удобно за разработка. Можете да проверите и двата режима, като просто промените стойността, подадена на `setDebugMode` в `Bootstrap.php`.


За да обобщим .[#toc-summary]
=============================

Имаме база данни с вписвания в блога и уеб приложение с два изгледа: първият показва обобщение на всички скорошни вписвания, а вторият - едно конкретно вписване.

{{priority: -1}}
{{sitename: Быстрый старт с Nette}}

Страница за индивидуално вписване

Нека да добавим още една страница към нашия блог, за да покажем съдържанието на един конкретен запис в блога.

Трябва да създадем нов метод за визуализация, който да вземе един конкретен запис в блога и да го предаде на шаблона. Това визуализиране в HomePresenter не е много приятно, защото става дума за запис в блог, а не за начална страница. Така че нека създадем нов клас PostPresenter и да го поставим в app/UI/Post/. Тя ще се нуждае от връзка с база данни, така че поставете отново кода за инжектиране на зависимости* там.

PostPresenter трябва да изглежда по следния начин:

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

Трябва да зададем правилното пространство от имена App\UI\Post за нашия презентатор. Това зависи от картографирането на водещия.

Методът renderShow изисква един аргумент – ID на публикацията на водещия. След това той зарежда тази публикация от базата данни и предава резултата на шаблона.

В шаблона Home/default.latte добавяме връзка към действието Post:show:

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

Тагът {link} генерира URL адрес, който насочва към действието Post:show. Този таг също така предава идентификатора на публикацията като аргумент.

Можем да напишем същото накратко, като използваме n:attribute:

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

Атрибутът n:href е подобен на тага {link}.

Шаблонът за действието Post:show все още не съществува. Можем да отворим връзка към тази публикация. Tracy ще покаже грешка, че app/UI/Post/show.latte не съществува. Ако видите друг отчет за грешка, вероятно трябва да активирате mod_rewrite на уеб сървъра си.

Затова ще създадем Post/show.latte с това съдържание:

{block content}

<p><a n:href="Home:default">← вернуться к списку постов</a></p>

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

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

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

Обмислете някои точки.

Първият ред започва дефиницията на именния блок, наречен content, който видяхме по-рано. Той ще се появи в шаблона на разположението.

Вторият ред съдържа обратна връзка към списъка с публикации в блога, така че потребителят да може да навигира плавно напред-назад из нашия блог. Отново използваме атрибута n:href, така че Nette ще се погрижи да генерира URL адреса вместо нас. Връзката сочи към действието default на водещия Home (може да напишете просто n:href="Home:", тъй като действието default може да бъде пропуснато).

Третият ред форматира времевия печат на публикацията, като използва филтъра date, както вече знаем.

Четвъртият ред показва заглавието на записа в блога като заглавие <h1>. Има една част, която може би не познавате, а именно n:block="title". Можете ли да познаете какво прави? Ако сте прочели внимателно предишните части, споменахме n: атрибуты. Ето още един пример. Това е равносилно на:

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

Просто казано, той заменя блок, наречен title. Блокът е дефиниран в шаблона за оформление (/app/UI/@layout.latte:11) и, както в случая на пренаписване на ООП, се пренаписва тук. Следователно <title> страници ще съдържа заглавието на показаната публикация. Премахнахме заглавието на страницата и всичко, от което се нуждаехме, беше n:block="title". Чудесно, нали?

Петият и последен ред на шаблона показва пълното съдържание на публикацията ви.

Проверка на ID на публикацията

Какво ще стане, ако някой промени URL адреса и вмъкне несъществуващ postId? Трябва да предоставим на потребителя хубава страница за грешка „Страницата не е намерена“. Нека да актуализираме метода render във файла PostPresenter.php:

public function renderShow(int $id): void
{
	$post = $this->database
		->table('posts')
		->get($id);
	if (!$post) {
		$this->error('Страница не найдена!');
	}

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

Ако публикацията не може да бъде намерена, при извикване на $this->error(...) ще се покаже страница 404 с хубаво и ясно съобщение. Обърнете внимание, че в режим на разработка няма да видите страницата за грешки. Вместо това Трейси ще покаже изключение с пълна информация, което е доста удобно за разработка. Можете да проверите и двата режима, като просто промените стойността, подадена на setDebugMode в Bootstrap.php.

За да обобщим

Имаме база данни с вписвания в блога и уеб приложение с два изгледа: първият показва обобщение на всички скорошни вписвания, а вторият – едно конкретно вписване.