Делаем вывод статей на сайте из базы данных
Итак, в прошлом уроке мы с вами создали класс для работы с базой данных и получили с его помощью две статьи. В этом уроке мы научимся выводить эти статьи на нашем сайте.
Давайте заглянем в наш шаблон.
templates/main/main.php
<?php include __DIR__ . '/../header.php'; ?>
<?php foreach ($articles as $article): ?>
<h2><?= $article['name'] ?></h2>
<p><?= $article['text'] ?></p>
<hr>
<?php endforeach; ?>
<?php include __DIR__ . '/../footer.php'; ?>
Как видим, здесь у нас требуются ключи ‘name’ и ‘text’. И они есть у наших статей! Нам достаточно только передать эти статьи в шаблон, чтобы вывести их.
src/MyProject/Controllers/MainController.php
<?php
namespace MyProject\Controllers;
use MyProject\Services\Db;
use MyProject\View\View;
class MainController
{
/** @var View */
private $view;
/** @var Db */
private $db;
public function __construct()
{
$this->view = new View(__DIR__ . '/../../../templates');
$this->db = new Db();
}
public function main()
{
$articles = $this->db->query('SELECT * FROM `articles`;');
$this->view->renderHtml('main/main.php', ['articles' => $articles]);
}
}
Как видим, нужные данные успешно были использованы в шаблоне.
Давайте добавим на нашем сайте ещё одну страничку, на которой будет выводиться только одна статья.
Давайте создадим новый контроллер.
src/MyProject/Controllers/ArticlesController.php
<?php
namespace MyProject\Controllers;
use MyProject\Services\Db;
use MyProject\View\View;
class ArticlesController
{
/** @var View */
private $view;
/** @var Db */
private $db;
public function __construct()
{
$this->view = new View(__DIR__ . '/../../../templates');
$this->db = new Db();
}
public function view()
{
echo 'Здесь будет получение статьи и рендеринг шаблона';
}
}
Добавим новый роут. Пусть наши статьи будут открываться по адресу типа: http://myproject.loc/articles/1, где вместо 1 может быть любой другой id статьи.
src/routes.php
<?php
return [
'~^articles/(\d+)$~' => [\MyProject\Controllers\ArticlesController::class, 'view'],
'~^$~' => [\MyProject\Controllers\MainController::class, 'main'],
];
Давайте проверим, что наш роут успешно обрабатывается:
Отлично, давайте теперь сделаем запрос в базу, в котором получим статью с нужным id.
src/MyProject/Controllers/ArticlesController.php
<?php
namespace MyProject\Controllers;
use MyProject\Services\Db;
use MyProject\View\View;
class ArticlesController
{
/** @var View */
private $view;
/** @var Db */
private $db;
public function __construct()
{
$this->view = new View(__DIR__ . '/../../../templates');
$this->db = new Db();
}
public function view(int $articleId)
{
$result = $this->db->query(
'SELECT * FROM `articles` WHERE id = :id;',
[':id' => $articleId]
);
var_dump($result);
}
}
Получили массив, в котором есть статья с id = 1.
Давайте посмотрим, что получится, если запросить статью с id = 2.
Всё снова хорошо отработало.
А что будет, если запросить статью, которой в базе нет?
Мы получим пустой массив. Отлично, теперь давайте попробуем обработать эти две ситуации.
public function view(int $articleId)
{
$result = $this->db->query(
'SELECT * FROM `articles` WHERE id = :id;',
[':id' => $articleId]
);
if ($result === []) {
// Здесь обрабатываем ошибку
return;
}
$this->view->renderHtml('articles/view.php', ['article' => $result[0]]);
}
Добавим шаблон для вывода одной статьи:
templates/articles/view.php
<?php include __DIR__ . '/../header.php'; ?>
<h1><?= $article['name'] ?></h1>
<p><?= $article['text'] ?></p>
<?php include __DIR__ . '/../footer.php'; ?>
Пришла пора добавить шаблон для страницы с ошибкой, когда что-то не найдено. Создадим ещё один шаблончик.
templates/errors/404.php
<h1>Страница не найдена</h1>
И будем подключать этот шаблон для случаев, когда наша статья не нашлась.
src/MyProject/Controllers/ArticlesController.php
...
public function view(int $articleId)
{
$result = $this->db->query(
'SELECT * FROM `articles` WHERE id = :id;',
[':id' => $articleId]
);
if ($result === []) {
$this->view->renderHtml('errors/404.php');
return;
}
$this->view->renderHtml('articles/view.php', ['article' => $result[0]]);
}
...
Попробуем теперь открыть страничку с несуществующей статьёй.
Однако, просто так написать о том, что страница не найдена не верно. Важно при этом вернуть код ответа для страницы, который даст понять поисковым системам, что эту страницу индексировать не нужно. Если мы откроем панель разработчика в Google Chrome и перезагрузим страничку, мы увидим, что текущий код ответа – 200. Это стандартный код ответа, говорящий о том, что со страничкой всё хорошо.
Нам же нужно вернуть код 404 – он говорит о том, что страница не найдена. Задать код ответа можно при помощи функции http_response_code(). В качестве аргумента ей передаётся код, который нужно вернуть.
Давайте отредактируем наш метод renderHtml() в классе View. Добавим возможность передавать код ответа.
src/MyProject/View/View.php
<?php
namespace MyProject\View;
class View
{
private $templatesPath;
public function __construct(string $templatesPath)
{
$this->templatesPath = $templatesPath;
}
public function renderHtml(string $templateName, array $vars = [], int $code = 200)
{
http_response_code($code);
extract($vars);
ob_start();
include $this->templatesPath . '/' . $templateName;
$buffer = ob_get_contents();
ob_end_clean();
echo $buffer;
}
}
По умолчанию, если мы не передадим третьим аргументом код, будет возвращён 200-ый, иначе – заданный нами.
Остаётся только добавить передачу нужного кода в том месте, где мы вызываем рендеринг страницы с ошибкой.
src/MyProject/Controllers/ArticlesController.php
<?php
namespace MyProject\Controllers;
use MyProject\Services\Db;
use MyProject\View\View;
class ArticlesController
{
/** @var View */
private $view;
/** @var Db */
private $db;
public function __construct()
{
$this->view = new View(__DIR__ . '/../../../templates');
$this->db = new Db();
}
public function view(int $articleId)
{
$result = $this->db->query(
'SELECT * FROM `articles` WHERE id = :id;',
[':id' => $articleId]
);
if ($result === []) {
$this->view->renderHtml('errors/404.php', [], 404);
return;
}
$this->view->renderHtml('articles/view.php', ['article' => $result[0]]);
}
}
Снова проверяем, обновив страничку.
Вжух! Получили нужный код ошибки.
Итак, мы с вами сделали вывод списка статей и вывод каждой статьи отдельно. Уже немало. Давайте теперь сделаем ссылки на странице со списком, которые будут вести на отдельную статью. Для этого нам нужно только немного поправить шаблон.
templates/main/main.php
<?php include __DIR__ . '/../header.php'; ?>
<?php foreach ($articles as $article): ?>
<h2><a href="/articles/<?= $article['id'] ?>"><?= $article['name'] ?></a></h2>
<p><?= $article['text'] ?></p>
<hr>
<?php endforeach; ?>
<?php include __DIR__ . '/../footer.php'; ?>
Зайдём в корень нашего сайтика и увидим, что теперь мы можем переходить по каждой статье отдельно.
На этом данный урок заканчивается, а в следующих мы научимся работать с базой данных, получая из неё объекты, а не массивы.
Текущая версия проекта на гитхабе.
Комментарии