Главная страница блога
Теперь мы создадим главную страницу, отображающую последние посты.
Прежде чем начать, необходимо знать хотя бы основы паттерна проектирования Model-View-Presenter (похожего на MVC):
- Модель (Model) – слой, работающий с данными. Полностью отделен от остальной части приложения. Общается только с презентером.
- Представление (View) – фронтенд-слой. Отображает запрашиваемые данные с помощью шаблонов и показывает их пользователю.
- Презентер (Presenter) (или Контроллер) – связующий слой. Презентер связывает Модель и Представление. Обрабатывает запросы, запрашивает данные у Модели и возвращает их в Представление.
В случае простых приложений, каким будет наш блог, весь модельный слой будет состоять только из запросов к базе данных – для этого пока не нужен дополнительный код. Для начала создадим только презентеры и шаблоны. В Nette у каждого презентера есть свои собственные шаблоны, поэтому мы будем создавать их одновременно.
Создание базы данных с помощью Adminer
Для хранения данных мы будем использовать базу данных MySQL, так как она наиболее распространена среди разработчиков веб-приложений. Однако, если вы не хотите ее использовать, смело выбирайте базу данных по своему усмотрению.
Теперь подготовим структуру базы данных, где будут храниться статьи нашего блога. Начнем очень просто – создадим только одну таблицу для постов.
Для создания базы данных мы можем скачать Adminer или другой ваш любимый инструмент для управления базами данных.
Откроем Adminer и создадим новую базу данных с именем quickstart
.
Создадим новую таблицу с именем posts
и следующими столбцами:
id
int, отметим autoincrement (AI)title
varchar, length 255content
textcreated_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 использует табы.
Передача подключения к базе данных
Презентер 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()
,
который передает данные из базы данных в шаблон (Представление).
Шаблоны находятся в 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}
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}
Если мы обновим браузер, увидим список всех постов. Список пока не
очень красивый и не цветной, поэтому мы можем добавить в файл
www/css/style.css
несколько 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 с несколькими постами. Приложение подключается к этой базе данных и выводит простой список этих постов в шаблон.