本稿では、返信画面を作成します。返信画面とは、自分宛の返信の投稿だけをタイムラインに表示させる画面です。
reply.php
で自分宛ての返信のみのタイムラインを表示させる
現時点では、投稿には返信先の情報がないので、その投稿がただの投稿か、誰かへの返信のための投稿かどうかの判断が出来ない状態です。そこで、返信の投稿であれば、スクリーン名が投稿の内容に含まれることを利用して、その投稿に返信先の情報(ユーザID)を追加できるようにします。
仕組みは以下の通りです。
- 投稿の内容に
@スクリーン名
が含まれる場合には返信だとみなす - スクリーン名からその返信先ユーザのIDを取得して投稿に情報として持たせる
- 投稿が持っている返信先のユーザIDが自分のものだけを返信画面のタイムラインに表示させる
- 投稿が誰かへの返信だった時、返信先のユーザIDを取得する関数を追加
- 返信先のユーザIDを保存する関数を追加
- 自分宛ての返信を取得する関数を追加
- タイムラインに表示させる
投稿の内容に@スクリーン名
が含まれるかどうかを調べ、含まれていた場合はその投稿は返信であるとする。
functions.php
に追記しましょう。
// @スクリーン名が含まれていた場合にそのユーザIDを取得する関数
function getReplyId(PDO $pdo, $text)
{
$at = preg_match('/@(?P<screen_name>[a-zA-Z0-9]+) /', $text, $mention);
if ($at) {
// スクリーン名からユーザIDをを返す
return getUserIdByScreenName($pdo, $mention["screen_name"]);
}
// 返信でなければNULLを返す
return null;
}
// スクリーン名からユーザIDを取得する関数
function getUserIdByScreenName(PDO $pdo, $screenName)
{
$sql = 'SELECT id FROM users WHERE `screen_name` = :screen_name';
$statement = $pdo->prepare($sql);
$statement->bindValue(':screen_name', $screenName, PDO::PARAM_STR);
$statement->execute();
if ($row = $statement->fetch(PDO::FETCH_ASSOC)) {
return $row['id'];
} else {
return null;
}
}
$at = preg_match('/@(?P<screen_name>[a-zA-Z0-9]+) /', $text, $mention);
@スクリーン名
が含まれているかどうかを調べるために、正規表現という表現法を使用します。正規表現とは、文字列のパターンを表現する表記法で、文字列の検索・置換を行うときに利用されます。この表現方法を利用すれば、たくさんの文章の中から容易に見つけたい文字列を検索することができます。今回は、上記のコードの/@(?P<screen_name>[a-zA-Z0-9]+) /
の部分が正規表現の部分です。
正規表現については、以下のリンクを参照して下さい。
preg_matchという関数は、正規表現検索を行うための関数です。
if ($at) {
//スクリーン名からユーザIDを取得した結果を返す
return getUserIdByScreenName($pdo, $mention["screen_name"]);
}
return null;
次に、上記のコードのif文で、もしマッチしていたらスクリーン名からユーザIDを取得する関数であるgetUserIdByScreenName()
を呼び出しています。getUserIdByScreenName()
の中を見てみると、
$sql = 'SELECT id FROM users WHERE `screen_name` = :screen_name';
より、スクリーン名で条件付けられたusers
テーブルのid
を取得していることがわかります。これで、返信先のユーザIDを取得することが出来ました。
1で、投稿が誰かへの返信だった時、返信先のユーザIDを取得する関数を作成しました。そこで、実際に投稿する時にこの関数を呼び出します。方法としては、以前作成した投稿するための関数であるwritePost()
を編集し、DBのposts
テーブルのin_reply_to_user_id
に返信先のユーザIDを保存できるようにします。
functions.php
のwritePost()
を変更しましょう。
function writePost(PDO $pdo, $id, $text)
{
// 以下を変更
$replyUserId = getReplyId($pdo, $text);
$sql = 'INSERT INTO posts (user_id,in_reply_to_user_id,text) VALUES (:user_id, :reply_user_id, :text)';
$statement = $pdo->prepare($sql);
$statement->bindValue(':user_id', $id, PDO::PARAM_INT);
$statement->bindValue(':reply_user_id', $replyUserId, PDO::PARAM_INT);
$statement->bindValue(':text', $text, PDO::PARAM_STR);
$statement->execute();
}
$replyUserId = getReplyId($pdo, $text);
この行で、1で作ったgetReplyId()
を呼び出しています。この関数は@スクリーン名
が含まれていた場合にそのユーザIDを取得するための関数でしたね。よって$replyUserId
には、返信先のユーザIDが入ります。また、もし投稿が返信ではなくただの投稿だった場合はNULL
が入ります。
...
$sql = 'INSERT INTO posts (user_id,in_reply_to_user_id,text) VALUES (:user_id, :reply_user_id, :text)';
...
$statement->bindValue(':reply_user_id', $replyUserId, PDO::PARAM_INT);
...
上記のようにin_reply_to_user_id
カラムに返信先のユーザIDが挿入されるように変更されました。
functions.php
に以下を追記しましょう。
// 自分宛ての返信だけを取得する
function getReplyTimeline(PDO $pdo, $userId)
{
$sql = 'SELECT * FROM posts WHERE `in_reply_to_user_id` = :user_id ORDER BY `created_at` DESC';
$statement = $pdo->prepare($sql);
$statement->bindValue(':user_id', $userId, PDO::PARAM_INT);
$statement->execute();
if ($rows = $statement->fetchAll(PDO::FETCH_ASSOC)) {
return $rows;
} else {
return false;
}
}
全ての投稿を取得していたgetTimeline()
と比較してみてください。
function getReplyTimeline(PDO $pdo, $userId)
{
$sql = 'SELECT * FROM posts WHERE `in_reply_to_user_id` = :user_id ORDER BY `created_at` DESC';
$statement = $pdo->prepare($sql);
$statement->bindValue(':user_id', $userId, PDO::PARAM_INT);
$statement->execute();
if ($rows = $statement->fetchAll(PDO::FETCH_ASSOC)) {
return $rows;
} else {
return false;
}
}
SQL文の中にWHERE in_reply_to_user_id = :user_id
が追加されています。
このように、WHERE 条件式
を追加すると、条件式に一致する行を取得することができるようになります。詳しい説明はMySQLリファレンスを見て下さい。
ここでは、in_reply_to_user_id
がuesr_id
のものだけをpostsテーブルから取得するという条件をつけています。もちろんここのuser_id
は自分のユーザIDです。
これで、自分宛ての返信を取得する関数を準備出来ました。あとは、表示させるだけです!
返信画面はreply.php
です。index.php
とほぼ同じになるので、index.php
をreply.php
にそのままコピペして下さい。その後、少しだけ編集していきます。
reply.php
の以下の3点を書き換えましょう。
<?php
// PHP部分
...
$user_id = $_SESSION['user_id'];
$db = connectDb();
// 以下を変更1
$posts = getReplyTimeline($db, $user_id);
// 変更1ここまで
...
<!-- ここからHTML部分 -->
...
<ul class="nav navbar-nav">
<!-- 以下を変更2 -->
<li><a href="./index.php">ホーム</a></li>
<li class="active"><a href="./reply.php">返信</a></li>
<!-- 変更2ここまで -->
</ul>
...
<!-- 全員の投稿表示領域の見出しの部分 -->
<div class="panel-heading">
<!-- 以下を変更3 -->
<h3 class="panel-title">あなた宛ての返信</h3>
<!-- 変更3ここまで -->
</div>
$posts = getReplyTimeline($db, $user_id);
$post
には3で作成したgetReplyTimeline()
の返り値である自分宛ての返信のみが入ります。あとは、投稿一覧表示の作成と同じです。
<li><a href="./index.php">ホーム</a></li>
<li class="active"><a href="./reply.php">返信</a></li>
Bootstrapでclass="active"
に対してCSSが当てられているので、それを適応させることができます。返信ボタンが押されているようなデザインに変わりましたね。
本稿の実装では、ページング機能は実装できていません。以前トップページのページング機能は実装しましたね。ほぼ同じなので、ページング機能の作成のテキストを見ながら、ページング機能を実装してみましょう!
以上で返信画面の作成は終わりです!ここまでで、Ditterの最低限の部分の実装は終わりました!お疲れ様です!!
これから先は、もっと細かい部分へと入ります。