記事ページ
次に、特定の 1 つの記事を表示する別のブログページを作成します。
特定の 1 つの記事を取得し、それをテンプレートに渡す新しい render
メソッドを作成する必要があります。このメソッドを HomePresenter
に置くのは、記事について話しているのであって、トップページについてではないため、あまりきれいではありません。そこで、app/Presentation/Post/
に PostPresenter
を作成しましょう。この Presenter
もデータベースに接続する必要があるため、ここでもデータベース接続を要求するコンストラクタを記述します。
したがって、PostPresenter
は次のようになります。
<?php
namespace App\Presentation\Post;
use Nette;
use Nette\Application\UI\Form;
final class PostPresenter extends Nette\Application\UI\Presenter
{
public function __construct(
private Nette\Database\Explorer $database,
) {
}
public function renderShow(int $id): void
{
$this->template->post = $this->database
->table('posts')
->get($id);
}
}
Presenter のマッピング
の設定に従う正しい名前空間 App\Presentation\Post
を指定することを忘れないでください。
renderShow
メソッドは 1 つの引数、つまり表示する特定の記事の ID
を必要とします。次に、この ID
を使用してデータベースから記事を読み込み、テンプレートに渡します。
Home/default.latte
テンプレートに Post:show
アクションへのリンクを挿入します。
...
<h2><a href="{link Post:show $post->id}">{$post->title}</a></h2>
...
{link}
タグは、Post:show
アクションを指す URL
アドレスを生成します。また、記事の ID を引数として渡します。
同じことを n:属性を使用して短縮して記述できます。
...
<h2><a n:href="Post:show $post->id">{$post->title}</a></h2>
...
n:href
属性は {link}
タグに似ています。
ただし、Post:show
アクションのテンプレートはまだ存在しません。この投稿へのリンクを開いてみることができます。Tracy は、Post/show.latte
テンプレートがまだ存在しないため、エラーを表示します。別のエラーメッセージが表示される場合は、おそらく
Web サーバーで mod_rewrite
を有効にする必要があります。
そこで、次の内容で Post/show.latte
テンプレートを作成します。
{block content}
<p><a n:href="Home:default">← 記事一覧に戻る</a></p>
<div class="date">{$post->created_at|date:'F j, Y'}</div>
<h1 n:block="title">{$post->title}</h1>
<div class="post">{$post->content}</div>
次に、テンプレートの各部分を見ていきましょう。
最初の行は、トップページと同様に “content”
という名前のブロック定義を開始します。このブロックは再びメインテンプレートに表示されます。ご覧のとおり、終了タグ
{/block}
がありません。これはオプションだからです。
次の行には、ブログ記事のリストに戻るリンクがあり、ユーザーは記事リストと特定の記事の間を簡単に移動できます。n:href
属性を使用しているため、Nette が自動的にリンクの生成を処理します。リンクは Home
Presenter の default
アクションを指します(default
という名前のアクションは省略でき、自動的に補完されるため、n:href="Home:"
と書くこともできます)。
3 行目は、すでにおなじみのフィルタを使用して日付の出力をフォーマットします。
4 行目は、HTML タグ <h1>
でブログの タイトル
を表示します。このタグには、おそらく知らない属性 (n:block="title"
)
が含まれています。何をするか推測できますか?前の部分を注意深く読んだ場合、これが
n:属性
であることはすでに知っています。これは、次と同等の別の例です。
{block title}<h1>{$post->title}</h1>{/block}
簡単に言えば、このブロックは title
という名前のブロックを再定義します。このブロックはすでにメイン layout テンプレート
(/app/Presentation/@layout.latte:11
) で定義されており、OOP
でのメソッドのオーバーライドと同様に、メインテンプレートのこのブロックは完全にオーバーライドされます。したがって、ページの
<title>
には表示されている記事のタイトルが含まれるようになり、これには 1
つの単純な属性 n:block="title"
を使用するだけで十分でした。素晴らしいですね。
テンプレートの 5 行目と最後の行は、特定の 1 つの記事の全文を表示します。
記事 ID の確認
誰かが URL の ID を変更して、存在しない id
を入力したらどうなるでしょうか?ユーザーに「ページが見つかりません」という種類のわかりやすいエラーを提供する必要があります。そこで、PostPresenter
の render メソッドを少し変更します。
public function renderShow(int $id): void
{
$post = $this->database
->table('posts')
->get($id);
if (!$post) {
$this->error('ページが見つかりません');
}
$this->template->post = $post;
}
記事が見つからない場合、$this->error(...)
を呼び出すことで、わかりやすいメッセージとともに 404
エラーページが表示されます。開発モード(localhost)では、このエラーページは表示されないことに注意してください。代わりに、例外の詳細を示す
Tracy
が表示されます。これは開発には非常に便利です。両方のモードを表示したい場合は、Bootstrap.php
ファイルの setDebugMode
メソッドの引数を変更するだけです。
まとめ
記事を含むデータベースと、2 つのビューを持つ Web アプリケーションがあります。1 つ目はすべての記事の概要を表示し、2 つ目は特定の 1 つの記事を表示します。