Tworzenie i edycja postów

To świetnie! Mamy super fajnego nowego bloga, ludzie zawzięcie dyskutują w komentarzach, a my mamy wreszcie trochę czasu na dalsze programowanie. Chociaż Adminer jest świetnym narzędziem, nie jest do końca idealny do pisania nowych postów na blogu. Najwyraźniej nadszedł właściwy czas na stworzenie prostego formularza do dodawania nowych postów bezpośrednio z aplikacji. Zróbmy to.

Zacznijmy od zaprojektowania interfejsu użytkownika:

  1. Na stronie głównej dodamy link “Napisz nowy post”.
  2. Ten link wyświetli formularz z tytułem i polem tekstowym na treść posta.
  3. Gdy klikniemy przycisk Zapisz, post zostanie zapisany w bazie danych.

Później dodamy również logowanie i dodawanie postów umożliwimy tylko zalogowanym użytkownikom. Ale to później. Jaki kod musimy napisać teraz, aby wszystko działało?

  1. Stworzymy nowy presenter z formularzem do dodawania postów.
  2. Zdefiniujemy callback, który uruchomi się po pomyślnym wysłaniu formularza i który zapisze nowy post do bazy danych.
  3. Stworzymy nowy szablon, na którym będzie ten formularz.
  4. Dodamy link do formularza w szablonie strony głównej.

Nowy presenter

Nowy presenter nazwiemy EditPresenter i zapiszemy w app/Presentation/Edit/. Musi on również połączyć się z bazą danych, więc ponownie napiszemy konstruktor, który będzie wymagał połączenia z bazą danych:

<?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,
	) {
	}
}

Formularz do zapisywania postów

Formularze i komponenty wyjaśniliśmy już przy tworzeniu komentarzy. Jeśli nadal nie jest to jasne, przejdź do tworzenia formularzy i komponentów, my tu poczekamy ;)

Teraz dodajmy tę metodę do presentera EditPresenter:

protected function createComponentPostForm(): Form
{
	$form = new Form;
	$form->addText('title', 'Tytuł:')
		->setRequired();
	$form->addTextArea('content', 'Treść:')
		->setRequired();

	$form->addSubmit('send', 'Zapisz i opublikuj');
	$form->onSuccess[] = $this->postFormSucceeded(...);

	return $form;
}

Zapisywanie nowego postu z formularza

Kontynuujemy dodaniem metody, która przetworzy dane z formularza:

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

	$this->flashMessage("Post został pomyślnie opublikowany.", 'success');
	$this->redirect('Post:show', $post->id);
}

Tylko szybkie podsumowanie: ta metoda pobiera dane z formularza, wstawia je do bazy danych, tworzy wiadomość dla użytkownika o pomyślnym zapisaniu posta i przekierowuje na stronę z nowym postem, dzięki czemu od razu zobaczymy, jak wygląda.

Strona do tworzenia nowego postu

Stwórzmy teraz szablon Edit/create.latte:

{block content}
<h1>Nowy post</h1>

{control postForm}

Wszystko powinno być już jasne. Ostatnia linia renderuje formularz, który stworzyliśmy w poprzednim kroku.

Moglibyśmy również stworzyć odpowiednią metodę renderCreate(), ale nie jest to konieczne. Nie potrzebujemy pobierać żadnych danych z bazy danych i przekazywać ich do szablonu, więc ta metoda byłaby pusta. W takich przypadkach metoda w ogóle nie musi istnieć.

Prawdopodobnie już wiesz, jak dodać link do EditPresenter i jego akcji create. Spróbuj to zrobić.

Wystarczy do pliku app/Presentation/Home/default.latte dodać:

<a n:href="Edit:create">Napisz nowy post</a>

Edycja postów

Teraz dodamy również możliwość edycji posta. Będzie to bardzo proste. Mamy już gotowy formularz postForm i możemy go użyć również do edycji.

Dodamy nową stronę edit do presentera 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());
}

I stworzymy kolejny szablon Edit/edit.latte:

{block content}
<h1>Edytuj post</h1>

{control postForm}

Zmodyfikujemy metodę postFormSucceeded(), która będzie mogła zarówno dodać nowy artykuł (tak jak robi to teraz), jak i edytować już istniejący artykuł:

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('Post został pomyślnie opublikowany.', 'success');
	$this->redirect('Post:show', $post->id);
}

Jeśli parametr id jest dostępny, oznacza to, że będziemy edytować post. W tym przypadku sprawdzimy, czy żądany post naprawdę istnieje, a jeśli tak, zaktualizujemy go w bazie danych. Jeśli parametr id nie jest dostępny, oznacza to, że powinien zostać dodany nowy post.

Skąd jednak weźmie się ten parametr id? Jest to parametr, który został przekazany do metody renderEdit.

Teraz możemy dodać link do szablonu app/Presentation/Post/show.latte:

<a n:href="Edit:edit $post->id">Edytuj post</a>

Podsumowanie

Blog jest teraz funkcjonalny, odwiedzający aktywnie go komentują, a my już nie potrzebujemy Adminera do publikacji. Aplikacja jest w pełni niezależna i każdy może dodać nowy post. Chwila, to chyba nie jest do końca w porządku, że ktokolwiek – i mam na myśli naprawdę ktokolwiek z dostępem do internetu – może dodawać nowe posty. Potrzebne jest jakieś zabezpieczenie, aby nowy post mógł dodać tylko zalogowany użytkownik. Zajmiemy się tym w następnym rozdziale.