記事の作成と編集
素晴らしい。とても格好いい新しいブログができて、人々はコメントで活発に話し合っていて、ようやくもう少しプログラムを書く時間ができました。Adminer は優れた道具ですが、新しいブログの記事を書くにはあまり心地よくありません。アプリケーションから直接、新しい記事を足す単純なフォームを作るころ合いかもしれません。やってみましょう。
まず利用者から見えるところを設計するところから始めます。
- トップページに「新しい記事を書く」のリンクを足します。
- このリンクは、タイトルの項目と記事の中身のテキストエリアを持つフォームを表示します。
- 保存のボタンを押すと、その記事はデータベースに保存されます。
あとで認証も足して、ログインした利用者だけが新しい記事を足せるようにします。とはいえそれはあとにしましょう。今すべてを動かすには、どんなコードを書く必要があるでしょうか。
- 記事を足すフォームを持つ新しいプレゼンターを作ります。
- フォームが正しく送信されたあとに呼ばれ、新しい記事をデータベースに保存するコールバックを定義します。
- そのフォームの新しいテンプレートを作ります。
- トップページのテンプレートにそのフォームへのリンクを足します。
新しいプレゼンター
新しいプレゼンターを EditPresenter と名付け、app/Presentation/Edit/EditPresenter.php
に置きましょう。これもデータベースにつなぐ必要があるので、ここでもデータベース接続を求めるコンストラクタを書きます。
<?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);
}
手短に説明します。フォームから値を取り出し、データベースに入れ、記事がうまく保存されたことを利用者に伝えるメッセージを作り、その記事が公開されたページへリダイレクトして、どう見えるかを確かめられるようにします。
新しい記事を作るページ
では Edit/create.latte のテンプレートを作りましょう。
{block content}
<h1>新しい記事</h1>
{control postForm}
もうすべて分かるはずです。最後の行が、たった今作ったフォームを描きます。
対応する renderCreate()
メソッドも作れますが、必要ありません。データベースからデータを取り出してテンプレートへ渡す必要がないので、そのメソッドは空になります。こうした場合、メソッドはまったくなくてかまいません。
記事を作るためのリンク
EditPresenter とその create
アクションへのリンクの足し方は、もうご存じでしょう。やってみてください。
app/Presentation/Home/default.latte ファイルに次を足すだけです。
<a n:href="Edit:create">新しい記事を書く</a>
記事を編集する
では既存の記事を編集できるようにしましょう。とても簡単です。すでに postForm
のフォームがあり、それを編集にも使えます。
EditPresenter に新しい edit のページを足します。
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
のパラメータが渡されていれば、記事を編集しているということです。その場合はその記事が本当に存在するかを確かめ、存在すればデータベースで更新します。id
が渡されていなければ、新しい記事を足すということです。
ところで id はどこから来るのでしょうか。それは renderEdit
メソッドに渡されたパラメータです。
これで app/Presentation/Post/show.latte のテンプレートにリンクを足せます。
<a n:href="Edit:edit $post->id">この記事を編集</a>
まとめ
ブログは動いていて、人々は次々とコメントし、新しい記事を足すのにもう Adminer に頼りません。すっかり独り立ちして、ふつうの人でもそこに投稿できます。でも待ってください。誰でも、つまりインターネット上の本当に誰でも私たちのブログに投稿できるのは、たぶんよくありません。ログインした利用者だけが投稿できるように、何らかの認証が要ります。それは次の章で足します。