Добавляем статьи в блог на PHP

25.09.2023 в 23:41
14440
+537

В этом уроке мы с вами добавим самый главный функционал блога – добавление новых записей.

В одном из прошлых уроков мы уже добавили роут /articles/add и соответствующий экшен ArticlesController->add(). Так он выглядит сейчас:

src/MyProject/Controllers/ArticlesController.php

public function add(): void
{
    $author = User::getById(1);

    $article = new Article();
    $article->setAuthor($author);
    $article->setName('Новое название статьи');
    $article->setText('Новый текст статьи');

    $article->save();

    $article->delete();

    var_dump($article);
}

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

templates/articles/add.php

<?php include __DIR__ . '/../header.php'; ?>
    <h1>Создание новой статьи</h1>
    <?php if(!empty($error)): ?>
        <div style="color: red;"><?= $error ?></div>
    <?php endif; ?>
    <form action="/articles/add" method="post">
        <label for="name">Название статьи</label><br>
        <input type="text" name="name" id="name" value="<?= $_POST['name'] ?? '' ?>" size="50"><br>
        <br>
        <label for="text">Текст статьи</label><br>
        <textarea name="text" id="text" rows="10" cols="80"><?= $_POST['text'] ?? '' ?></textarea><br>
        <br>
        <input type="submit" value="Создать">
    </form>
<?php include __DIR__ . '/../footer.php'; ?>

Теперь сделаем набросок для контроллера, чтобы просто увидеть нашу форму.

src/MyProject/Controllers/ArticlesController.php

public function add(): void
{
    $this->view->renderHtml('articles/add.php');
}

Посмотрим на результат:
Форма добавления статей

Итак, в форме у нас есть 2 поля: name и text. На их основе мы должны научиться создавать статьи. Кроме того, в контроллере у нас также есть свойство user – текущий пользователь. Его нужно будет указывать автором при создании статей. Если мы соберем все эти три значения – мы сможем создать статью.

Первым делом нужно убедиться, что пользователь авторизован. Если это не так – будем кидать исключение в контроллере и ловить его во фронт-контроллере. Назовём такое исключение UnauthorizedException.

src/MyProject/Exceptions/UnauthorizedException.php

<?php

namespace MyProject\Exceptions;

class UnauthorizedException extends \Exception
{
}

Добавляем проверку в самом начале экшена.

src/MyProject/Controllers/ArticlesController.php

public function add(): void
{
    if ($this->user === null) {
        throw new UnauthorizedException();
    }

    $this->view->renderHtml('articles/add.php');
}

Обрабатываем исключение во фронт-контроллере. Добавляем в конце еще один catch.

www/index.php

...
} catch (\MyProject\Exceptions\UnauthorizedException $e) {
    $view = new \MyProject\View\View(__DIR__ . '/../templates/errors');
    $view->renderHtml('401.php', ['error' => $e->getMessage()], 401);
}

И, наконец, добавляем шаблон для ошибки.

templates/errors/401.php

<?php include __DIR__ . '/../header.php'; ?>
    <h1>Вы не авторизованы</h1>
    Для доступа к этой странице нужно <a href="/users/login">войти на сайт</a>
<?php include __DIR__ . '/../footer.php'; ?>

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

Затем входим на сайт и видим, что ошибка пропала и нам снова доступна форма для создания статьи.
Добавление статьи доступно

Теперь можно создать в модели статьи метод для создания новой статьи.

src/MyProject/Models/Articles/Article.php

public static function createFromArray(array $fields, User $author): Article
{
    if (empty($fields['name'])) {
        throw new InvalidArgumentException('Не передано название статьи');
    }

    if (empty($fields['text'])) {
        throw new InvalidArgumentException('Не передан текст статьи');
    }

    $article = new Article();

    $article->setAuthor($author);
    $article->setName($fields['name']);
    $article->setText($fields['text']);

    $article->save();

    return $article;
}

Дописываем экшен:

src/MyProject/Controllers/ArticlesController.php

public function add(): void
{
    if ($this->user === null) {
        throw new UnauthorizedException();
    }

    if (!empty($_POST)) {
        try {
            $article = Article::createFromArray($_POST, $this->user);
        } catch (InvalidArgumentException $e) {
            $this->view->renderHtml('articles/add.php', ['error' => $e->getMessage()]);
            return;
        }

        header('Location: /articles/' . $article->getId(), true, 302);
        exit();
    }

    $this->view->renderHtml('articles/add.php');
}

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

Заполняем формочку по адресу http://myproject.loc/articles/add
Создание статьи

И вуаля – создалась новая статья.

Созданная статья

А теперь – за домашку.

Текущая версия проекта на гитхабе.

loader
25.09.2023 в 23:41
14440
+537
Домашнее задание

Сделайте так, чтобы добавлять статьи могли только пользователи с правами админа. Если это не так - бросайте исключение с новым типом - Forbidden. При этом страница должна вернуть код 403.

Комментарии
Этот урок набрал набрал достаточно большое количество комментариев и дальнейшее его комментирование отключено. Если вы хотели убедиться в правильности выполнения ДЗ или у вас возник вопрос по уроку, посмотрите ранее добавленные комментарии, кликнув по кнопке ниже. Скорее всего вы найдете там то, что искали. Если это не помогло - задайте вопрос в чате в телеграме - https://t.me/php_zone
Логические задачи с собеседований