Сторінка окремого запису

Давайте додамо в наш блог ще одну сторінку, на якій відображатиметься вміст одного конкретного запису блогу.

Нам потрібно створити новий метод render, який буде отримувати один конкретний запис блогу і передавати його в шаблон. Мати це подання в 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 для нашого презентера. Це залежить від mapping presenter.

Метод 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: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". Чудово, чи не так?

П'ятий і останній рядок шаблону відображає повний зміст вашого поста.

Перевірка ідентифікатора поста

Що станеться, якщо хтось змінить 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 з красивим і зрозумілим повідомленням. Зверніть увагу, що в режимі розробки ви не побачите сторінку помилки. Натомість Tracy покаже виняток із повною інформацією, що досить зручно для розробки. Ви можете перевірити обидва режими, просто змінивши значення, що передається в setDebugMode на Bootstrap.php.

Підіб'ємо підсумок

У нас є база даних із записами блогу і веб-додаток із двома поданнями: перше відображає зведення всіх останніх записів, а друге – один конкретний запис.