Skip to content

Latest commit

 

History

History
262 lines (192 loc) · 10.3 KB

reply.md

File metadata and controls

262 lines (192 loc) · 10.3 KB

返信画面の作成

本稿では、返信画面を作成します。返信画面とは、自分宛の返信の投稿だけをタイムラインに表示させる画面です。

完成図

reply

要求仕様

reply.phpで自分宛ての返信のみのタイムラインを表示させる

現時点では、投稿には返信先の情報がないので、その投稿がただの投稿か、誰かへの返信のための投稿かどうかの判断が出来ない状態です。そこで、返信の投稿であれば、スクリーン名が投稿の内容に含まれることを利用して、その投稿に返信先の情報(ユーザID)を追加できるようにします。

仕組みは以下の通りです。

  1. 投稿の内容に@スクリーン名が含まれる場合には返信だとみなす
  2. スクリーン名からその返信先ユーザのIDを取得して投稿に情報として持たせる
  3. 投稿が持っている返信先のユーザIDが自分のものだけを返信画面のタイムラインに表示させる

作成手順

  1. 投稿が誰かへの返信だった時、返信先のユーザIDを取得する関数を追加
  2. 返信先のユーザIDを保存する関数を追加
  3. 自分宛ての返信を取得する関数を追加
  4. タイムラインに表示させる

1. 投稿が誰かへの返信だった時、返信先のユーザIDを取得する関数を追加

投稿の内容に@スクリーン名が含まれるかどうかを調べ、含まれていた場合はその投稿は返信であるとする。

コード

functions.phpに追記しましょう。

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を取得することが出来ました。

2. 返信先のユーザIDを保存する関数を追加

1で、投稿が誰かへの返信だった時、返信先のユーザIDを取得する関数を作成しました。そこで、実際に投稿する時にこの関数を呼び出します。方法としては、以前作成した投稿するための関数であるwritePost()を編集し、DBのpostsテーブルのin_reply_to_user_idに返信先のユーザIDを保存できるようにします。

コード

functions.phpwritePost()を変更しましょう。

functions.php

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が挿入されるように変更されました。

3. 自分宛ての返信を取得する関数を追加

コード

functions.phpに以下を追記しましょう。

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_iduesr_idのものだけをpostsテーブルから取得するという条件をつけています。もちろんここのuser_idは自分のユーザIDです。

これで、自分宛ての返信を取得する関数を準備出来ました。あとは、表示させるだけです!

4. タイムラインに表示させる

返信画面はreply.phpです。index.phpとほぼ同じになるので、index.phpreply.phpにそのままコピペして下さい。その後、少しだけ編集していきます。

コード

reply.phpの以下の3点を書き換えましょう。

reply.php

<?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の最低限の部分の実装は終わりました!お疲れ様です!!

これから先は、もっと細かい部分へと入ります。

今回使った構文や関数

参考