記事だけのコンテンツであれば、今までの実装で、「一覧、作成、編集、削除」機能が備わっています。
しかし、今回はコメント機能もつけたいと思うので、記事の詳細ページを作りましょう。
その詳細ページでコメントできるものとします。
メインページの改修
さて、記事編集画面、削除機能でやったように、メインページに詳細ページへのリンクを作成しましょう。
例のごとく、左に+
マークがついた行を追記してください。
<table> <tr> <td>記事ID</td> <td>タイトル</td> <td>本文</td> <td>投稿日</td> + <td></td> <td></td> <td></td> </tr> <?php while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { ?> <tr> <td><?php echo $row['id']; ?></td> <td><?php echo $row['title']; ?></td> <td><?php echo $row['content']; ?></td> <td><?php echo $row['time']; ?></td> + <td><a href="detail_post.php?id=<?php echo $row['id']; ?>">詳細</a></td> <td><a href="edit_post.php?id=<?php echo $row['id']; ?>">編集</a></td> <td><a href="delete_post.php?id=<?php echo $row['id']; ?>">削除</a></td> </tr> <?php } ?> </table>
詳細ページのファイル名はdetail_post.php
とします。
そのページでは対象記事IDを表示させたいので、GETでid
を渡します。
<a href="detail_post.php?id=<?php echo $row['id']; ?>">詳細</a>
記事詳細ページの実装
記事詳細ページの実装ですが、記事編集画面、削除機能の編集画面とPHP部分は同様です。
そのため、ヒントのサンプルコードを記載します。
後々のため、コメントを新規作成できるリンクだけつけておきます。
GETでpost_id
を渡していますが、この説明は次項でします。
<a href="create_comment.php?post_id=<?php echo $id ?>">この記事にコメントする</a>
サンプル
detail_post.php
リファクタリング
さて、ここでこんなことを思った方がいるかもしれません。
あれ、同じようなコードを書いているから一まとめにできないかな?
それは非常に感性が良いと思います。
正直、記事編集画面と詳細画面はPHPで似たようなコードが多いです。
ここをfunction.php
で関数にしてしまいましょう。
このように、コードを再整備することを リファクタリング といいます。
$idが空だったらメインページにリダイレクトさせる
このコードはedit_post.php
、detail_post.php
の両方に存在します。
// もし、$idが空であったらmain.phpにリダイレクト // 不正なアクセス対策 if (empty($id)) { header("Location: main.php"); exit; }
これは関数にできそうです。
そのため、function.php
に追加しましょう!
関数名はredirect_main_unless_parameter
とします。
/** * 引数の値が空だった場合、main.phpにリダイレクトする * @param integer $param * @return void */ function redirect_main_unless_parameter($param) { if (empty($param)) { header("Location: main.php"); exit; } }
引数名を$param
とすることで、$id
だけでなく他の要素で使用しても違和感がないです。
さて、この関数が用意できたので、edit_post.php
、detail_post.php
を書き換えましょう。
左端に-
が付いているコードは消してください。
左端に+
が付いているコードは代わりに追加してください。
- // もし、$idが空であったらmain.phpにリダイレクト - // 不正なアクセス対策 - if (empty($id)) { - header("Location: main.php"); - exit; - } + redirect_main_unless_parameter($id);
1行になってスッキリしましたね。
postsテーブルから1件取得する部分
正直、下記のコードも全く同じです。
try { // PDOのインスタンスを生成 $pdo = db_connect(); // SQL文の準備 $sql = "SELECT * FROM posts WHERE id = :id"; // プリペアドステートメントの作成 $stmt = $pdo->prepare($sql); // idのバインド $stmt->bindParam('id', $id); $stmt->execute(); } catch (PDOException $e) { // エラーメッセージの出力 echo 'Error: ' . $e->getMessage(); // 終了 die(); } // 結果が1行取得できたら if ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { $id = $row['id']; $title = $row['title']; $content = $row['content']; } else { // 対象のidでレコードがない => 不正な画面遷移 echo "対象のデータがありません。"; }
さて、関数名はどうしましょうか。。。
今回はposts
テーブルからid
で1件取得してくるので、find_post_by_id
としましょう。
/** * 引数で与えられたidでpostsテーブルを検索する * もし対象のレコードがなければmain.phpに遷移させる * @param integer $id * @return array */ function find_post_by_id($id) { // PDOのインスタンスを生成 $pdo = db_connect(); try { // SQL文の準備 $sql = "SELECT * FROM posts WHERE id = :id"; // プリペアドステートメントの作成 $stmt = $pdo->prepare($sql); // idのバインド $stmt->bindParam('id', $id); // 実行 $stmt->execute(); } catch (PDOException $e) { // エラーメッセージの出力 echo 'Error: ' . $e->getMessage(); // 終了 die(); } // 結果が1行取得できたら if ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { return $row; } else { redirect_main_unless_parameter($row); } }
もし、結果が1行も取得できなかったら、わざわざ結果がないことを表示する必要はあるでしょうか?
その場合はメインページに戻してしまいましょう。
先ほど作成したredirect_main_unless_parameter
が使えます!
さぁ、edit_post.php
、detail_post.php
を書き換えましょう。
なんと、try ~ catch
の部分が下記の5行で済みます!(コメントがなければ4行)
$row = find_post_by_id($id); // 関数から取得した値を格納 $id = $row['id']; $title = $row['title']; $content = $row['content'];