Сторінка з дописом
Тепер ми створимо ще одну сторінку блогу, яка буде відображати один конкретний допис.
Нам потрібно створити новий render-метод, який отримає одну конкретну
статтю і передасть її в шаблон. Мати цей метод у HomePresenter не дуже
гарно, оскільки ми говоримо про статтю, а не про головну сторінку.
Створимо PostPresenter у app/Presentation/Post/. Цей presenter також потребує
підключення до бази даних, тому тут ми знову напишемо конструктор, який
вимагатиме підключення до бази даних.
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, який
підпорядковується налаштуванню мапування 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:атрибута:
...
<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
presenter'а Home (можна також написати n:href="Home:", оскільки дія з
назвою default може бути пропущена, вона доповниться
автоматично).
Третій рядок форматує виведення дати за допомогою фільтра, який ми вже знаємо.
Четвертий рядок відображає заголовок блогу в HTML-тегу
<h1>. Цей тег містить атрибут, який ви, можливо, не знаєте
(n:block="title"). Вгадаєте, що він робить? Якщо ви уважно читали
попередню частину, то вже знаєте, що це n:атрибут. Це ще один їх
приклад, який є еквівалентним до:
{block title}<h1>{$post->title}</h1>{/block}
Простіше кажучи, цей блок перевизначає блок з назвою title. Цей
блок вже визначений у головному layout шаблоні
(/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.
Підсумок
У нас є база даних з дописами та веб-застосунок, який має два представлення – перше відображає огляд усіх дописів, а друге – один конкретний допис.