Головна сторінка блогу

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

Перш ніж ми почнемо, ви маєте знати хоча б деякі основи патерну проєктування Model-View-Presenter (аналогічного MVC)):

  • Модель – рівень маніпулювання даними. Він повністю відокремлений від іншої частини додатка і спілкується тільки з презентерами.
  • Вид (або _Представлення_) – зовнішній рівень визначення. Він відображає запитувані дані користувачеві за допомогою шаблонів.
  • Презентер (або _Контролер_) – рівень з'єднання. Презентер з'єднує модель і вигляд. Обробляє запити, запитує дані у моделі і потім передає їх поточному поданню.

У разі дуже простого застосунку, такого як наш блог, шар Model фактично складатиметься тільки із запитів до самої бази даних – нам не потрібен додатковий PHP-код для цього. Нам потрібно створити тільки шари Presenter і View. У Nette у кожного презентера є свої подання, тому ми продовжимо роботу з ними обома одночасно.

Створення бази даних за допомогою Adminer

Для зберігання даних ми будемо використовувати базу даних MySQL, оскільки це найбільш поширений вибір серед веб-розробників. Але якщо вам це не подобається, не соромтеся використовувати базу даних за своїм вибором.

Давайте підготуємо базу даних, у якій зберігатимуться записи нашого блогу. Почнемо з однієї таблиці для постів.

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

Давайте відкриємо Adminer і створимо нову базу даних під назвою quickstart.

Створіть нову таблицю з іменем posts і додайте до неї ці стовпці:

  • id int, натисніть на автоінкремент (AI)
  • title varchar, довжина 255
  • content text
  • created_at timestamp

Це має виглядати наступним чином:

CREATE TABLE `posts` (
	`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
	`title` varchar(255) NOT NULL,
	`content` text NOT NULL,
	`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB CHARSET=utf8;

Дуже важливо використовувати сховище таблиць InnoDB. Причину ви побачите пізніше. Поки що просто створіть все за інструкцією і натисніть кнопку Зберегти. Або використовуйте повний код створення таблиці та кнопку SQL-запит в Adminer.

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

INSERT INTO `posts` (`id`, `title`, `content`, `created_at`) VALUES
(1,	'Статья первая',	'Lorem ipusm dolor one',	CURRENT_TIMESTAMP),
(2,	'Статья вторая',	'Lorem ipsum dolor two',	CURRENT_TIMESTAMP),
(3,	'Статья третья',	'Lorem ipsum dolor three',	CURRENT_TIMESTAMP);

Підключення до бази даних

Тепер, коли база даних створена і в ній є кілька постів, саме час відобразити їх на нашій новій блискучій сторінці.

По-перше, нам потрібно повідомити нашому додатку, яку базу даних використовувати. Конфігурація підключення до бази даних зберігається у файлі config/common.neon. Встановіть з'єднання DSN і свої облікові дані. Це має виглядати так:

database:
	dsn: 'mysql:host=127.0.0.1;dbname=quickstart'
	user: *укажите здесь имя пользователя*
	password: *укажите здесь пароль*

Пам'ятайте про відступи під час редагування цього файлу. Формат NEON приймає і пробіли, і табуляцію, але не те й інше разом! У файлі конфігурації у веб-проекті за замовчуванням використовується табуляція.

Впровадження підключення до бази даних

Презентер (розташований у app/UI/Home/HomePresenter.php), який буде перераховувати статті, потребує підключення до бази даних. Для цього змініть конструктор таким чином:

<?php
namespace App\UI\Home;

use Nette;

final class HomePresenter extends Nette\Application\UI\Presenter
{
	public function __construct(
		private Nette\Database\Explorer $database,
	) {
	}

	// ...
}

Завантаження постів з бази даних

Тепер давайте витягнемо пости з бази даних і передамо їх у шаблон, який потім відобразить HTML-код. Для цього і призначений так званий метод render:

public function renderDefault(): void
{
	$this->template->posts = $this->database
		->table('posts')
		->order('created_at DESC')
		->limit(5);
}

Тепер у презентері є один метод рендерингу renderDefault(), який передає дані в подання під назвою default. Шаблони презентера можна знайти в app/UI/{PresenterName}/{viewName}.latte, тому в даному випадку шаблон буде розташований в app/UI/Home/default.latte. У шаблоні тепер доступна змінна $posts, яка містить пости з бази даних.

Шаблон

Існує загальний шаблон для всієї сторінки (називається layout (макет), із заголовком, таблицями стилів, нижнім колонтитулом тощо), а також специфічні шаблони для кожного виду (наприклад, для відображення списку записів блогу), які можуть перевизначати деякі частини шаблону макета.

За замовчуванням шаблон макета розташовується у файлі app/UI/@layout.latte, який містить:

...
{include content}
...

{include content} вставляє блок з ім'ям content в основний шаблон. Ви можете визначити його в шаблонах кожного подання. У нашому випадку ми відредагуємо файл app/UI/Home/default.latte таким чином:

{block content}
	Привет, мир!
{/block}

Він визначає блок контенту, який буде вставлено в макет. Якщо ви оновите браузер, то побачите сторінку з текстом “Привіт, світ!” (у вихідному коді також із HTML заголовком і колонтитулом, визначеними в @layout.latte).

Давайте відобразимо записи блогу – для цього відредагуємо шаблон таким чином:

{block content}
	<h1 n:block="title">Мой блог</h1>

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

		<h2>{$post->title}</h2>

		<div>{$post->content|truncate:256}</div>
	</div>
	{/foreach}
{/block}

Якщо ви оновите браузер, ви побачите список записів вашого блогу. Список не дуже вигадливий або барвистий, тому не соромтеся додати трохи блискучого CSS у www/css/style.css, а потім вставте посилання на цей файл у макет (файл @layout.latte):

	...
	<link rel="stylesheet" href="{$basePath}/css/style.css">
</head>
...

Тег {foreach} перебирає всі пости, передані шаблону у змінній $posts, і виводить фрагмент HTML-коду для кожного поста. Точно так само, як це робиться в PHP-коді.

Функція |date називається фільтром. Фільтри використовуються для форматування виведення. Цей конкретний фільтр перетворює дату (наприклад, 2013-04-12) у більш читабельну форму (12.04.2013). Фільтр |truncate усікає рядок до вказаної максимальної довжини і додає три крапки в кінець, якщо рядок усічений. Оскільки це попередній перегляд, немає сенсу відображати повний зміст статті. Інші фільтри за замовчуванням можна знайти в документації або ви можете створити свої власні, якщо це необхідно.

І ще одне. Ми можемо зробити код трохи коротшим і, отже, простішим. Ми можемо замінити теги Latte на n:attributes таким чином:

{block content}
	<h1>My blog</h1>

	<div n:foreach="$posts as $post" class="post">
		<div class="date">{$post->created_at|date:'F j, Y'}</div>

		<h2>{$post->title}</h2>

		<div>{$post->content}</div>
	</div>
{/block}

n:foreach просто обгортає div блоком foreach (він робить те саме, що й попередній блок коду).

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

У нас є дуже проста база даних MySQL з деякими записами в блозі. Додаток підключається до бази даних і відображає простий список постів.