Создание и редактирование постов

Это здорово! У нас есть супер крутой новый блог, люди активно обсуждают в комментариях, и у нас наконец-то есть немного времени на дальнейшее программирование. Хотя Adminer — отличный инструмент, он не совсем идеален для написания новых постов в блог. Вероятно, пришло время создать простую форму для добавления новых постов прямо из приложения. Давайте сделаем это.

Начнем с проектирования пользовательского интерфейса:

  1. На главной странице добавим ссылку “Написать новый пост”.
  2. Эта ссылка отобразит форму с заголовком и текстовой областью для содержимого поста.
  3. Когда мы нажмем кнопку Сохранить, пост сохранится в базе данных.

Позже мы также добавим вход в систему и разрешим добавление постов только вошедшим пользователям. Но это позже. Какой код нам нужно написать сейчас, чтобы все заработало?

  1. Создадим новый презентер с формой для добавления постов.
  2. Определим обратный вызов (callback), который запустится после успешной отправки формы и который сохранит новый пост в базе данных.
  3. Создадим новый шаблон, на котором будет эта форма.
  4. Добавим ссылку на форму в шаблон главной страницы.

Новый презентер

Новый презентер назовем EditPresenter и сохраним в app/Presentation/Edit/. Ему также необходимо подключиться к базе данных, поэтому здесь снова напишем конструктор, который будет требовать подключение к базе данных:

<?php
namespace App\Presentation\Edit;

use Nette;
use Nette\Application\UI\Form;

final class EditPresenter extends Nette\Application\UI\Presenter
{
	public function __construct(
		private Nette\Database\Explorer $database,
	) {
	}
}

Форма для сохранения постов

Формы и компоненты мы уже объяснили при создании комментариев. Если это все еще неясно, пройдите создание форм и компонентов, мы здесь пока подождем ;)

Теперь добавим этот метод в презентер EditPresenter:

protected function createComponentPostForm(): Form
{
	$form = new Form;
	$form->addText('title', 'Заголовок:')
		->setRequired();
	$form->addTextArea('content', 'Содержимое:')
		->setRequired();

	$form->addSubmit('send', 'Сохранить и опубликовать');
	$form->onSuccess[] = $this->postFormSucceeded(...);

	return $form;
}

Сохранение нового поста из формы

Продолжаем добавлением метода, который обработает данные из формы:

private function postFormSucceeded(array $data): void
{
	$post = $this->database
		->table('posts')
		->insert($data);

	$this->flashMessage('Пост был успешно опубликован.', 'success');
	$this->redirect('Post:show', $post->id);
}

Краткое резюме: этот метод получает данные из формы в виде массива $data, вставляет их в базу данных, создает сообщение для пользователя об успешном сохранении поста и перенаправляет на страницу с новым постом, чтобы мы сразу увидели, как он выглядит.

Страница для создания нового поста

Теперь создадим шаблон Edit/create.latte:

{block content}
<h1>Новый пост</h1>

{control postForm}

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

Мы могли бы создать также соответствующий метод renderCreate(), но это не обязательно. Нам не нужно получать какие-либо данные из базы данных и передавать их в шаблон, так что этот метод был бы пустым. В таких случаях метод может вообще не существовать.

Ссылка на создание постов

Вероятно, вы уже знаете, как добавить ссылку на EditPresenter и его действие create. Попробуйте это сделать.

Достаточно в файл app/Presentation/Home/default.latte добавить:

<a n:href="Edit:create">Написать новый пост</a>

Редактирование постов

Теперь добавим также возможность редактирования поста. Это будет очень просто. У нас уже есть готовая форма postForm, и мы можем использовать ее и для редактирования.

Добавим новую страницу edit в презентер EditPresenter:

public function renderEdit(int $id): void
{
	$post = $this->database
		->table('posts')
		->get($id);

	if (!$post) {
		$this->error('Post not found');
	}

	$this->getComponent('postForm')
		->setDefaults($post->toArray());
}

И создадим еще один шаблон Edit/edit.latte:

{block content}
<h1>Редактировать пост</h1>

{control postForm}

И изменим метод postFormSucceeded(), который сможет как добавлять новую статью (как он делает это сейчас), так и редактировать уже существующую статью:

private function postFormSucceeded(array $data): void
{
	$id = $this->getParameter('id');

	if ($id) {
		$post = $this->database
			->table('posts')
			->get($id);
		$post->update($data);

	} else {
		$post = $this->database
			->table('posts')
			->insert($data);
	}

	$this->flashMessage('Пост был успешно опубликован.', 'success');
	$this->redirect('Post:show', $post->id);
}

Если доступен параметр id, это означает, что мы будем редактировать пост. В этом случае мы получаем пост из базы данных и обновляем его новыми данными $data. Если параметр id недоступен, то это означает, что должен быть добавлен новый пост, поэтому мы вставляем данные $data.

Но откуда возьмется этот параметр id? Это параметр, который был передан в метод renderEdit().

Теперь мы можем добавить ссылку в шаблон app/Presentation/Post/show.latte:

<a n:href="Edit:edit $post->id">Редактировать пост</a>

Резюме

Блог теперь функционален, посетители активно его комментируют, и нам больше не нужен Adminer для публикации. Приложение полностью независимо, и кто угодно может добавить новый пост. Так, стоп, это, наверное, не совсем правильно, что кто угодно – и я имею в виду действительно кого угодно с доступом в интернет – может добавлять новые посты. Требуется какая-то защита, чтобы новый пост мог добавить только вошедший пользователь. Это мы рассмотрим в следующей главе.