Главная страница блога
Создадим главную страницу, показывающую ваши последние записи.
Прежде чем начать, вам стоит знать хотя бы основы о шаблоне проектирования Model-View-Presenter (похожем на MVC):
- Model – слой, работающий с данными. Он полностью отделён от остального приложения. Общается он только с презентером.
- View – слой отображения. Он отрисовывает запрошенные данные с помощью шаблонов и показывает их пользователю.
- Presenter (или контроллер) – соединяющий слой. Презентер соединяет Model и View. Он обрабатывает запросы, просит у Model данные и затем передаёт их во View.
В случае простого приложения вроде нашего блога весь слой модели будет состоять только из запросов к базе данных – никакого дополнительного PHP-кода для этого нам пока не нужно. Так что для начала мы создадим только презентеры и шаблоны. В Nette у каждого презентера свои шаблоны, так что создавать их будем одновременно.
Создание базы данных с помощью Adminer
Для хранения данных мы воспользуемся базой данных MySQL, потому что это самый частый выбор среди веб-разработчиков. Однако если вы не хотите её использовать, спокойно выберите базу данных по своему вкусу.
Подготовим структуру базы данных, в которой будут храниться записи нашего блога. Начать можно совсем просто, всего с одной таблицы для записей.
Чтобы создать базу данных, мы можем скачать Adminer либо использовать другой инструмент управления базами данных, который вам больше нравится.
Откроем Adminer и создадим новую базу данных под названием
quickstart.
Создайте новую таблицу с именем posts и добавьте эти столбцы:
idint, отметьте autoincrement (AI)titlevarchar, длина 255contenttextcreated_attimestamp
Должно получиться так:

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 ipsum 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 использует табуляции.
Внедрение соединения с базой данных
Презентеру 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);
}
Теперь у презентера есть один метод отрисовки renderDefault(),
который передаёт данные из базы данных в шаблон (View). Шаблоны находятся
в app/Presentation/{ИмяПрезентера}/{имяПредставления}.latte, так что в
данном случае шаблон находится в app/Presentation/Home/default.latte. В шаблоне
теперь доступна переменная с именем $posts, содержащая записи,
полученные из базы данных.
Шаблон
Для всего сайта у нас есть главный шаблон (называемый layout, содержащий шапку, стили, подвал, …) и отдельные шаблоны для каждого представления (например, для отображения записей блога), которые могут переопределять части главного шаблона.
По умолчанию шаблон макета находится в app/Presentation/@layout.latte и
содержит:
...
{include content}
...
Тег {include content} вставляет в главный шаблон блок с именем
content. Этот блок мы определим в шаблонах отдельных представлений.
В нашем случае мы изменим файл Home/default.latte вот так:
{block content}
Hello World
{/block}
Тем самым определён блок content,
который будет вставлен в главный макет. Если вы снова обновите браузер,
вы увидите страницу с текстом “Hello World” (в исходном коде вместе с
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}
Если вы обновите браузер, вы увидите список записей своего блога.
Список пока не слишком нарядный и цветной, так что смело добавьте красивые стили CSS в файл
www/css/style.css и подключите его в макете:
...
<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 с несколькими записями. Приложение подключается к этой базе данных и выводит в шаблоне простой список этих записей.