Страница с публикация

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

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

PostPresenter би могъл да изглежда така:

<?php
namespace App\Presentation\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\Presentation\Post, което подлежи на настройката на картографиране на презентери.

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

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

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

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

Същото можем да запишем съкратено с помощта на n:атрибут:

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

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

За действието Post:show обаче все още не съществува шаблон. Можем да опитаме да отворим връзката към тази публикация. Tracy ще покаже грешка, защото шаблонът 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:'F j, Y'}</div>

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

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

Сега ще разгледаме отделните части на шаблона.

Първият ред започва дефиницията на блок с име “content”, точно както беше на началната страница. Този блок отново ще бъде показан в главния шаблон. Както виждате, липсва крайният таг {/block}. Той всъщност е незадължителен.

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

Третият ред форматира извеждането на датата с помощта на филтъра, който вече познаваме.

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

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

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

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

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

Какво ще се случи, ако някой промени ID в URL адреса и въведе някое несъществуващо id? Трябва да предложим на потребителя хубава грешка от типа “страницата не е намерена”. Ще променим малко render метода в PostPresenter:

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

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

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

Резюме

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