Създаване и редактиране на публикации

Това е страхотно! Имаме супер готин нов блог, хората усилено дискутират в коментарите и най-накрая имаме малко време за още програмиране. Въпреки че 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('Публикацията не е намерена');
	}

	$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 за публикуване. Приложението е напълно независимо и всеки може да добави нова публикация. Но почакайте, това вероятно не е съвсем наред, че всеки – и имам предвид наистина всеки с достъп до интернет – може да добавя нови публикации. Необходима е някаква защита, така че само влезлият потребител да може да добави нова публикация. Ще разгледаме това в следващата глава.