Створення та редагування дописів

Це чудово! У нас є супер крутий новий блог, люди активно обговорюють у коментарях, і у нас нарешті є трохи часу на подальше програмування. Хоча Adminer — чудовий інструмент, він не зовсім ідеальний для написання нових дописів у блозі. Мабуть, настав час створити просту форму для додавання нових дописів безпосередньо з застосунку. Давайте зробимо це.

Почнемо з проектування користувацького інтерфейсу:

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

Пізніше ми також додамо вхід і дозволимо додавати дописи лише залогіненим користувачам. Але це пізніше. Який код нам потрібно написати зараз, щоб усе працювало?

  1. Створимо новий presenter з формою для додавання дописів.
  2. Визначимо callback, який запуститься після успішного надсилання форми та збереже новий допис у базу даних.
  3. Створимо новий шаблон, на якому буде ця форма.
  4. Додамо посилання на форму в шаблон головної сторінки.

Новий presenter

Новий presenter назвемо 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,
	) {
	}
}

Форма для збереження дописів

Форми та компоненти ми вже пояснювали при створенні коментарів. Якщо це все ще незрозуміло, перегляньте створення форм та компонентів, ми поки що зачекаємо тут ;)

Тепер додамо цей метод до presenter'а 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);
}

Лише короткий підсумок: цей метод отримує дані з форми, вставляє їх у базу даних, створює повідомлення для користувача про успішне збереження допису та перенаправляє на сторінку з новим дописом, щоб ми одразу побачили, як він виглядає.

Сторінка для створення нового допису

Тепер створимо шаблон 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 до presenter'а EditPresenter:

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

	if (!$post) {
		$this->error('Допис не знайдено'); // Translate string
	}

	$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, це означає, що ми будемо редагувати допис. У цьому випадку ми перевіримо, чи дійсно існує потрібний допис, і якщо так, оновимо його в базі даних. Якщо параметр id відсутній, це означає, що слід додати новий допис.

Але звідки береться цей параметр id? Це параметр, який був переданий у метод renderEdit.

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

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

Підсумок

Блог тепер функціонує, відвідувачі активно коментують його, і нам більше не потрібен Adminer для публікації. Застосунок повністю незалежний, і будь-хто може додати новий допис. Зачекайте, це, мабуть, не зовсім правильно, що будь-хто — і я маю на увазі справді будь-кого з доступом до Інтернету — може додавати нові дописи. Потрібна якась безпека, щоб новий допис міг додати лише залогінений користувач. Про це ми поговоримо в наступному розділі.