10
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

よくわかるPHPの教科書/Twitter風ひとこと掲示板 に「いいね」機能を追加してみた

Last updated at Posted at 2019-05-09

初めてのQiitaへの投稿です。
現在、プログラミングスクールQUELCODEでプログラミングを学んでいます。
※QUELCODEについて同期が書いたブログ
https://ktg6.com/quelcode-experience-information
https://toshi65811.hatenablog.jp/entry/2019/01/11/132810
https://yukimasablog.com/school-quelcode

カリキュラムの中で、PHPについては「よくわかるPHPの教科書【PHP7対応版】」を使いました。
そのテキストのChapter.6で「Twitter風ひとこと掲示板」を作る章があります。
テキストを3周し、3周目のときにはテキストの内容を作るだけでなくいいね機能を作ってみたので、まとめてみます。

同じテキストを使ってPHPを学んでいる初心者の方の参考になればと思います。(私はこのテキストで初めてPHPに触れました)
基本的には私が手を加えた部分だけ記載するため(テキストの内容はあまり書き写さない方がいいと思うので)、このテキストを使い、かつ、Chapter.6までやった方で無いと前提がよく分からないと思いますのでご了承下さい。

目的

テキストChapter.6の「Twitter風ひとこと掲示板」に本家Twitterを参考にいいね機能を追加し、PHP学習の理解を深める

追加する機能概要

いいねを記録するテーブルを作る
②メッセージ一覧ページに、いいねのハートマーク / いいねされている件数 を表示する欄を作る
③メッセージ一覧ページでハートマークの横にいいねの件数を表示
④メッセージ一覧ページでいいねする機能を作る(色無しのハートマークを押すと、ハートマークが赤くなりいいねの件数が1件増える)※1メッセージに対して1ユーザーがいいね出来るのは1回だけ)
⑤メッセージ一覧ページでいいねを取り消す機能を作る(ハートマークが赤い状態で押すといいねが取り消されてハートマークが色無しになりいいねの件数が1件減る)

本家Twitterを参考に、このように追加してみます。
※本家のようにいいねしたユーザー一覧のページも作ろうかと思ったのですが、スクールのカリキュラムを先に進めたくなったのでそこまではやりませんでした。

機能詳細

※丸数字は機能概要と連動してます。

###1. (①)テーブル「likes」を作り、いいねを記録出来るようにする
capture3.png
※プログラムの中で使用する項目はliked_post_idpressed_member_idのみ

###2. (②)index.phpにて、メッセージ一覧の投稿日時と削除リンクの間に、ハートマークといいねの件数表示出来るように③④⑤を作って行く
表示イメージ: capture2.png

###3. (③)index.phpにて、いいねされた件数を判別するために必要な情報を作り出す
テキストでは元々以下のような情報を作り出しているので、これに必要な情報を加えていく

メンバーのニックネーム メンバーの写真のパス postsテーブルの全項目
members.name members.picture posts.*
テキストのSQL
テキストのSQL
SELECT m.name, m.picture, p.* FROM members m, posts p WHERE m.id=p.member_id ORDER BY p.created DESC LIMIT ?, 5
// ?には、何番目の投稿から取得するか(最大5件ずつなので)を意味する$startを入れる
######3-1. 「likes」テーブルからメッセージIDごとの`いいね`された件数を取得する
|いいねされたメッセージID|いいねされた件数| |:-:|:-:| |liked_post_id|COUNT(liked_post_id) AS li_cnt|
SQL
index.php
SELECT liked_post_id, COUNT(liked_post_id) AS li_cnt FROM likes GROUP BY liked_post_id) AS li
######3-2. テキストのSQLのFROM posts 部分の「posts」テーブルについて、メッセージIDごとに`いいね`された件数を付加した状態に置き換える その情報を作成するために、「posts」テーブルと3-1の情報をposts.idとliked_post_idで結合する
postsテーブルの全項目 いいねされた件数
posts.* li_cnt
postsを置き換える情報を作るためのSQL
index.php
SELECT posts.*, li_cnt FROM posts LEFT JOIN 
                            (SELECT liked_post_id, COUNT(liked_post_id) AS li_cnt FROM likes GROUP BY liked_post_id) AS li ON posts.id=li.liked_post_id)
テキストのSQLのFROMの`posts`部分に上のSQLをはめ込んで完成させる
SQL
index.php
SELECT m.name, m.picture, p.* FROM members m,
(SELECT posts.*, li_cnt FROM posts LEFT JOIN 
                                   (SELECT liked_post_id, COUNT(liked_post_id) AS li_cnt FROM likes GROUP BY liked_post_id) AS li ON posts.id=li.liked_post_id) p
WHERE m.id=p.member_id ORDER BY p.created DESC LIMIT ?, 5
SQLをprepareステートメントで実行する
index.phpに追加した処理
index.php
$posts = $db->prepare('SELECT m.name, m.picture, p.* FROM members m,
                                                         (SELECT posts.*, li_cnt FROM posts LEFT JOIN 
                                                                 (SELECT liked_post_id, COUNT(liked_post_id) AS li_cnt FROM likes GROUP BY liked_post_id) AS li ON posts.id=li.liked_post_id) p
                       WHERE m.id=p.member_id ORDER BY p.created DESC LIMIT ?, 5;');
$posts->bindParam(1, $start, PDO::PARAM_INT);
$posts->execute();
###4. (④⑤) index.phpにて「likes」テーブルより自身が`いいね`したメッセージIDの一覧情報を作り出す
    いいねしたメッセージID|
    :-:|
    liked_post_id|
SQL
index.php
SELECT liked_post_id FROM likes WHERE pressed_member_id=?
// ?には自身のIDとして$_SESSION['id']が入る
SQLをprepareステートメントで実行し、後で使用するため配列に入れておく
index.phpに追加した処理
index.php
$pressedMessages = $db->prepare('SELECT liked_post_id FROM likes WHERE pressed_member_id=?');
$pressedMessages->bindParam(1, $_SESSION['id'], PDO::PARAM_INT);
$pressedMessages->execute();
$pressedMsg = array();
foreach ($pressedMessages as $pMsg) {
  $pressedMsg[] = $pMsg;
}

###5. (③④⑤) index.phpにて(最大で)5件出力するメッセージ一覧の繰り返し処理(foreach)の中に、取得した情報を組み込む
######5-1. 4で取得したメッセージIDの中に現在のメッセージID(最大で5件繰り返すforeachの中の$post['id'])が存在していれば目印をつける($likeAriに値を入れる)

index.phpに追加した処理
index.php
$likeAri = 0; // $likeAriは毎回初期化
for($i=0; $i<count($pressedMsg); $i++) {
    if ($pressedMsg[$i]['liked_post_id'] == $post['id']) {
        $likeAri = $post['id'];
        break;
    }
}
// 変数名のネーミングセンスが微妙過ぎる
###### 5-2. メッセージ一覧ページに、`いいね`のハートマーク / `いいね`されている件数 を表示する 5-1で設定した`$likeAri`より、`いいね`していたら赤いハートを、`いいね`していなかったら色無しのハートを、ハートの隣には取得した件数を表示する
index.phpに追加した処理
index.php
<?php if ($likeAri > 0) { ?>
    <a class="like" style="color:#F33;" href="like_delete.php?id=<?php echo h($post['id']); ?>">&#9829;</a><span class="likeCount"><?php echo h($post['li_cnt']); ?></span>
<?php } else { ?>
    <a class="like" href="like_insert.php?id=<?php echo h($post['id']); ?>">&#9825;</a><span class="likeCount"><?php echo h($post['li_cnt']); ?></span>
<?php } ?>
// ハートマークはただの記号のハートで、画像とかは使ってません

###6. (④⑤) ハートマークを押した場合の動きを作る

6-1. (④)色無しのハートマークを押したら新規作成したlike_insert.phpにて「likes」テーブルにいいねした記録をINSERTし、index.phpに戻る
like_insert.php
like_insert.php
session_start();
require('dbconnect.php');

if (isset($_SESSION['id'])) {

  // いいねが登録済みかチェックするため情報を取得する
  $likes = $db->prepare('SELECT COUNT(liked_post_id) AS like_cnt FROM (SELECT liked_post_id FROM likes WHERE liked_post_id=? AND pressed_member_id=? GROUP BY liked_post_id) A');
  $likes->execute(array(
    $_REQUEST['id'], // liked_post_id いいねしようとしているメッセージのid
    $_SESSION['id']  // pressed_member_id いいねしようとしているメンバーのid
  ));
  $like = $likes->fetch();

  // いいねしようとしている投稿に対して、すでにいいねをしていないかチェックする
  if ($like['like_cnt'] == 0) {
    // いいねを登録する
    $like_ins = $db->prepare('INSERT INTO likes SET liked_post_id=?, pressed_member_id=?, created=NOW()');
    $like_ins->execute(array(
      $_REQUEST['id'], // liked_post_id いいねしようとしているメッセージのid
      $_SESSION['id']  // pressed_member_id いいねしようとしているメンバーのid
    ));
  }
}

header('Location: index.php');
exit();
###### 6-2. (⑤) ハートマークが赤い状態で押したら新規作成したlike_delete.phpにて「likes」テーブルから`いいね`した記録をDELETEし、index.phpに戻る
like_delete.php
like_delete.php
session_start();
require('dbconnect.php');

if (isset($_SESSION['id'])) {
  // いいねが登録済みかチェックするため情報を取得する
  $likes = $db->prepare('SELECT COUNT(liked_post_id) AS like_cnt FROM (SELECT liked_post_id FROM likes WHERE liked_post_id=? AND pressed_member_id=? GROUP BY liked_post_id) A');
  $likes->execute(array(
    $_REQUEST['id'], // liked_post_id いいねを取消しようとしているメッセージのid
    $_SESSION['id']  // pressed_member_id いいねを取消しようとしているメンバーのid
  ));
  $like = $likes->fetch();

  // いいねを取消しようとしている投稿が1件のみか確認する
  if ($like['like_cnt'] == 1) {
    // いいねを削除する
    $like_ins = $db->prepare('DELETE FROM likes WHERE liked_post_id=? AND pressed_member_id=?');
    $like_ins->execute(array(
      $_REQUEST['id'], // liked_post_id いいねしようとしているメッセージのid
      $_SESSION['id']  // pressed_member_id いいねしようとしているメンバーのid
    ));
  }
}

header('Location: index.php');
exit();

完成

いいねする前:ハートマークが色なし(横の数字は自分以外にいいねが3件ある例)
capture1.png

いいねするとハートが赤くなって、数字が増える
capture2.png

もう一度ハートマークを押すと、いいねが取り消されて色なし3件に戻る
※1メッセージに対して1人1回しかいいね出来ないようにしてある
capture1.png

振り返り

PHPの学習というよりは、SQLがメインだったかなという気がします。
試行錯誤している内にCOBOLっぽい感じになってきてしまった気がする(現職がCOBOLer)ので、もっとスマートに書けるようになりたいです。

10
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?