Чат PHP-разработчиков
Логические задачи с собеседований
Делаем вывод статей в блоге

Делаем вывод статей на сайте из базы данных

Итак, в прошлом уроке мы с вами создали класс для работы с базой данных и получили с его помощью две статьи. В этом уроке мы научимся выводить эти статьи на нашем сайте.

Давайте заглянем в наш шаблон.

templates/main/main.php

Код доступен только после покупки курса ООП в PHP.

Как видим, здесь у нас требуются ключи ‘name’ и ‘text’. И они есть у наших статей! Нам достаточно только передать эти статьи в шаблон, чтобы вывести их.

src/MyProject/Controllers/MainController.php

Код доступен только после покупки курса ООП в PHP.

Снова обновим страничку.
Статьи отрендеренные

Как видим, нужные данные успешно были использованы в шаблоне.
Давайте добавим на нашем сайте ещё одну страничку, на которой будет выводиться только одна статья.

Давайте создадим новый контроллер.

src/MyProject/Controllers/ArticlesController.php

Код доступен только после покупки курса ООП в PHP.

Добавим новый роут. Пусть наши статьи будут открываться по адресу типа: http://myproject.loc/articles/1, где вместо 1 может быть любой другой id статьи.

src/routes.php

Код доступен только после покупки курса ООП в PHP.

Давайте проверим, что наш роут успешно обрабатывается:
ЧПУ

Отлично, давайте теперь сделаем запрос в базу, в котором получим статью с нужным id.

src/MyProject/Controllers/ArticlesController.php

Код доступен только после покупки курса ООП в PHP.

Посмотрим на результат снова.
Одна статья в виде массива

Получили массив, в котором есть статья с id = 1.
Давайте посмотрим, что получится, если запросить статью с id = 2.
Вторая статья в виде массива

Всё снова хорошо отработало.
А что будет, если запросить статью, которой в базе нет?
Пустой массив

Мы получим пустой массив. Отлично, теперь давайте попробуем обработать эти две ситуации.

Код доступен только после покупки курса ООП в PHP.

Добавим шаблон для вывода одной статьи:

templates/articles/view.php

Код доступен только после покупки курса ООП в PHP.

И проверим, что всё ок.
Вывод статьи в шаблоне

Пришла пора добавить шаблон для страницы с ошибкой, когда что-то не найдено. Создадим ещё один шаблончик.

templates/errors/404.php

Код доступен только после покупки курса ООП в PHP.

И будем подключать этот шаблон для случаев, когда наша статья не нашлась.

src/MyProject/Controllers/ArticlesController.php

Код доступен только после покупки курса ООП в PHP.

Попробуем теперь открыть страничку с несуществующей статьёй.
Страница не найдена

Однако, просто так написать о том, что страница не найдена не верно. Важно при этом вернуть код ответа для страницы, который даст понять поисковым системам, что эту страницу индексировать не нужно. Если мы откроем панель разработчика в Google Chrome и перезагрузим страничку, мы увидим, что текущий код ответа – 200. Это стандартный код ответа, говорящий о том, что со страничкой всё хорошо.
200 код ответа

Нам же нужно вернуть код 404 – он говорит о том, что страница не найдена. Задать код ответа можно при помощи функции http_response_code(). В качестве аргумента ей передаётся код, который нужно вернуть.

Давайте отредактируем наш метод renderHtml() в классе View. Добавим возможность передавать код ответа.

src/MyProject/View/View.php

Код доступен только после покупки курса ООП в PHP.

По умолчанию, если мы не передадим третьим аргументом код, будет возвращён 200-ый, иначе – заданный нами.

Остаётся только добавить передачу нужного кода в том месте, где мы вызываем рендеринг страницы с ошибкой.

src/MyProject/Controllers/ArticlesController.php

Код доступен только после покупки курса ООП в PHP.

Снова проверяем, обновив страничку.
404 код ответа

Вжух! Получили нужный код ошибки.

Итак, мы с вами сделали вывод списка статей и вывод каждой статьи отдельно. Уже немало. Давайте теперь сделаем ссылки на странице со списком, которые будут вести на отдельную статью. Для этого нам нужно только немного поправить шаблон.

templates/main/main.php

Код доступен только после покупки курса ООП в PHP.

Зайдём в корень нашего сайтика и увидим, что теперь мы можем переходить по каждой статье отдельно.
Ссылки на статьи

На этом данный урок заканчивается, а в следующих мы научимся работать с базой данных, получая из неё объекты, а не массивы.

Читайте также
Комментарии


tomsonst
tomsonst

Долго провозился с использованием переменной в запросе

public function view(int $articleId)
{
    $result = $this->db->query(
        'SELECT * FROM `articles` WHERE id = :id;',
        [':id' => $articleId]
    );
    $author =  $this->db->query('SELECT nickname FROM users WHERE id = "'.$result[0][1].'"');

    if ($result === []) {
        $this->view->renderHtml('errors/404.php');
        return;
    }

    $this->view->renderHtml('articles/view.php', ['article' => $result[0], 'author' =>$author[0][0]]);
}
ivashkevich
ivashkevich

Автора стоит получать только после того, как проверили что массив не пустой.

demyanovpaul@yandex.ru
demyanovpaul@yandex.ru

В экшне ArticlesController::view() после получения статьи, добавьте ещё один запрос на получение автора этой статьи из таблицы users. Выведите nickname автора в шаблоне.

С помощью Join соединил две таблички и без лишних обращений к базе забрал себе пользователей, дополнительно в списке статей тоже вывел авторов. Курс по БД прошел не зря=)

//MainController.php
public function main()
    {
        $articles = $this->db->query('SELECT * FROM `articles` a JOIN `users` u ON a.author_id = u.id');
        $this->view->renderHtml('main/main.php', ['articles' => $articles]);
    }
//main.php
<?php include __DIR__ . '/../main/header.php'; ?>
<?php foreach ($articles as $article): ?>
    <h2><a href="/articles/<?= $article['id'] ?>"><?= $article['name'] ?></a></h2>
    <p><?= $article['text'] ?></p>
    <p>Автор: <i><?= $article['nickname'] ?></i></p>
    <hr>
<?php endforeach; ?>
<?php include __DIR__ . '/../main/footer.php'; ?>
//ArticlesController.php
public function view(int $articleId)
    {
        $result = $this->db->query('SELECT * FROM `articles` a JOIN `users` u ON a.author_id = u.id WHERE a.id = :id;',[':id' => $articleId]);

        if ($result === []) {
            $this->view->renderHtml('errors/404.php',[],404);
            return;
        }

        $this->view->renderHtml('articles/view.php', ['article' => $result[0]]);
    }
//view.php
<?php include __DIR__ . '/../main/header.php'; ?>
    <h1><?= $article['name'] ?></h1>
    <p><?= $article['text'] ?></p>
    <p>Автор: <i><?= $article['nickname'] ?></i></p>
<?php include __DIR__ . '/../main/footer.php'; ?>
ivashkevich
ivashkevich

Хорошо, так тоже можно)

computerix
computerix
public function view(int $articleId)
    {
        $result = $this->db->query(
            'SELECT * FROM `articles` left join `users` on articles.author_id = users.id where articles.id = :id;' ,
            [':id' => $articleId]
        );
        if ($result === []) {
            $this->view->renderHtml('errors/404.php', [], 404);
            return;
        }

        $this->view->renderHtml('articles/view.php', ['article' => $result[0]]);
    }
}
ivashkevich
ivashkevich

А почему использовали LEFT JOIN?

computerix
computerix

Да как-то так придумалось) Неверно?

ivashkevich
ivashkevich

Нужно понимать разницу между разными типами JOIN-ов - прочитайте о них. Конкретно здесь должен быть INNER JOIN.

computerix
computerix
public function view(int $articleId)
    {
        $result = $this->db->query(
            'SELECT * FROM `articles` inner join `users` on articles.author_id = users.id where articles.id = :id;' ,
            [':id' => $articleId]
        );
        if ($result === []) {
            $this->view->renderHtml('errors/404.php', [], 404);
            return;
        }

        $this->view->renderHtml('articles/view.php', ['article' => $result[0]]);
    }
}
Todd
Todd

ArticlesController

    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;
        }

        $result_user = $this->db->query(
            'SELECT `nickname` FROM `users` WHERE id = :id',
            [':id' => $result[0]['author_id']]
        );

        if ($result_user === []) {
            $result_user[0]['nickname'] = 'не известно';
        }

        $this->view->renderHtml('articles/view.php', ['article' => $result[0], 'nickname' => $result_user[0]['nickname']]);
    }

view

<?php include __DIR__ . '/../header.php'; ?>
    <h1><?= $article['name'] ?></h1>
    <p><?= $article['text'] ?></p>
    <p>Имя автора: <?= $nickname ?></p>
<?php include __DIR__ . '/../footer.php'; ?>
AxLT
AxLT
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]]);
}

на участке:

 if ($result === []) {
        $this->view->renderHtml('errors/404.php');
        return;

renderHtml должен принимать на вход два аргумента, и при таком коде у меня ошибка, исправил на:

 $this->view->renderHtml('errors/404.php', []);

Вопрос почему у вас работает иначе)?

Todd
Todd

А можно увидеть функцию renderHtml ? второй аргумент должен иметь дефолтное значение, ощущение что у Вас он не задан, но могу ошибаться)

ivashkevich
ivashkevich

Привет! Вот код:

public function renderHtml(string $templateName, array $vars = [], int $code = 200)
    {
        http_response_code($code);

        extract($this->extraVars);
        extract($vars);

        ob_start();
        include $this->templatesPath . '/' . $templateName;
        $buffer = ob_get_contents();
        ob_end_clean();

        echo $buffer;
    }

Второй аргумент по умолчанию равен пустому массиву.

AxLT
AxLT

Да действительно упустил
Спасибо

AxLT
AxLT

Сделал так

 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;
        }

        $author = $this->db->query(
            'SELECT nickname FROM users WHERE id = :id',
            [':id' => $result[0][1]]
        );            
        $this->view->renderHtml('articles/view.php', ['article' => $result[0], 'author' => $author[0][0]]);
    }

И есть один вопрос, View на вход принимает $articleId, так вот мне не совсем понятно каким образом эта переменная задается ив какой именно момент она получает свои значения "1" "2"

ivashkevich
ivashkevich

Норм сделал. То что и нужно было.

AxLT
AxLT

Там снизу еще вопрос есть)

ivashkevich
ivashkevich

Не понял вопроса. Напиши по нему лучше в личку в телеге.

bildep@gmail.com
bildep@gmail.com

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;
        }

        $author = $this->db->query(
            'SELECT * FROM `users` WHERE id = :id;',
            [':id' => $result[0]["author_id"]]
        );

        $result[0]['author'] = $author[0]["nickname"];

        $this->view->renderHtml('articles/view.php', ['article' => $result[0]]);
    }
}

view.php

<?php include __DIR__ . '/../header.php'; ?>
    <h1><?= $article['name'] ?></h1>
    <p><?= $article['text'] ?></p>
    <p>Автор: <?= $article['author'] ?></p>
<?php include __DIR__ . '/../footer.php'; ?>