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

Тепер ми створимо головну сторінку, що відображатиме останні пости.

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

  • Модель – шар, що працює з даними. Він повністю відокремлений від решти застосунку. Спілкується лише з presenter'ом.
  • Представлення – front-end шар. Відображає запитані дані за допомогою шаблонів і показує їх користувачеві.
  • Presenter (або Controller) – сполучний шар. Presenter пов'язує Модель і Представлення. Обробляє запити, запитує дані у Моделі та повертає їх до Представлення.

У випадку простих застосунків, як наш блог, весь модельний шар складатиметься лише із запитів до бази даних – для цього поки що не потрібен додатковий код. Для початку створимо лише presenter'и та шаблони. У Nette кожен presenter має свої власні шаблони, тому ми будемо створювати їх одночасно.

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

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

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

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

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

Створимо нову таблицю з назвою posts та з такими стовпцями:

  • id int, позначимо autoincrement (AI)
  • title varchar, length 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. За мить ми покажемо чому. Поки що просто виберіть його та натисніть зберегти.

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

INSERT INTO `posts` (`id`, `title`, `content`, `created_at`) VALUES
(1,	'Article One',	'Lorem ipusm dolor one',	CURRENT_TIMESTAMP),
(2,	'Article Two',	'Lorem ipsum dolor two',	CURRENT_TIMESTAMP),
(3,	'Article Three',	'Lorem ipsum dolor three',	CURRENT_TIMESTAMP);

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

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

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

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

При редагуванні цього файлу будьте уважні з відступами рядків. Формат NEON приймає як відступи за допомогою пробілів, так і відступи за допомогою табуляції, але не обидва одночасно. Стандартний конфігураційний файл у Web Project використовує табуляцію.

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

Presenter HomePresenter, який буде відповідати за виведення статей, потребує підключення до бази даних. Для його отримання ми використаємо конструктор, який виглядатиме так:

<?php
namespace App\Presentation\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);
}

Presenter тепер містить один рендер-метод renderDefault(), який передає дані з бази даних до шаблону (Представлення). Шаблони розміщені в app/Presentation/{PresenterName}/{viewName}.latte, тому в цьому випадку шаблон знаходиться в app/Presentation/Home/default.latte. У шаблоні тепер буде доступна змінна $posts, в якій містяться пости, отримані з бази даних.

Шаблон

Для всього веб-сайту у нас є головний шаблон (який називається layout, містить заголовок, стилі, підвал,…) та конкретні шаблони для кожного представлення (View) (наприклад, для відображення постів у блозі), які можуть перевизначити деякі частини головного шаблону.

За замовчуванням шаблон layout знаходиться в app/Presentation/@layout.latte і містить:

...
{include content}
...

Запис {include content} вставляє в головний шаблон блок з назвою content. Його ми будемо визначати в шаблонах окремих представлень (View). У нашому випадку файл Home/default.latte змінимо наступним чином:

{block content}
	Привіт Світ
{/block}

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

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

{block content}
	<h1>Мій блог</h1>

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

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

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

Якщо ми оновимо браузер, побачимо список усіх постів. Список поки що не дуже гарний і не кольоровий, тому ми можемо додати до файлу www/css/style.css кілька CSS стилів і підключити його в layout'і:

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

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

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

Ще одна річ. Попередній код можна скоротити та спростити. Цього досягнемо заміною Latte тегів на n:атрибути:

{block content}
	<h1>Мій блог</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|truncate:256}</div>
	</div>
{/block}

Атрибут n:foreach обгортає div блоком foreach (працює абсолютно так само, як попередній код).

Підсумок

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