Главная страница блога
Давайте создадим главную страницу, на которой будут отображаться ваши последние посты.
Прежде чем мы начнем, вы должны знать хотя бы некоторые основы паттерна проектирования Model-View-Presenter (аналогичного MVC):
- Модель — уровень манипулирования данными. Он полностью отделен от остальной части приложения и общается только с презентерами.
- Вид (или _Представление_) — внешний уровень определения. Он отображает запрашиваемые данные пользователю с помощью шаблонов.
- Презентер (или _Контроллер_) — уровень соединения. Презентер соединяет модель и вид. Обрабатывает запросы, запрашивает данные у модели и затем передает их текущему представлению.
В случае очень простого приложения, такого как наш блог, слой Model фактически будет состоять только из запросов к самой базе данных — нам не нужен дополнительный PHP-код для этого. Нам нужно создать только слои Presenter и View. В Nette у каждого презентера есть свои представления, поэтому мы продолжим работу с ними обоими одновременно.
Создание базы данных с помощью Adminer
Для хранения данных мы будем использовать базу данных MySQL, поскольку это наиболее распространенный выбор среди веб-разработчиков. Но если вам это не нравится, не стесняйтесь использовать базу данных по своему выбору.
Давайте подготовим базу данных, в которой будут храниться записи нашего блога. Начнём с одной таблицы для постов.
Для создания базы данных мы можем скачать Adminer, или вы можете использовать другой инструмент для управления базами данных.
Давайте откроем Adminer и создадим новую базу данных под названием
quickstart
.
Создайте новую таблицу с именем posts
и добавьте в нее эти
столбцы:
id
int, нажмите на автоинкремент (AI)title
varchar, длина 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. Причину вы увидите позже. Пока что просто создайте всё по инструкции и нажмите кнопку Сохранить. Либо используйте полный код создания таблицы и кнопку 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 с некоторыми записями в блоге. Приложение подключается к базе данных и отображает простой список постов.