初めての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」を作り、いいね
を記録出来るようにする
※プログラムの中で使用する項目はliked_post_id
とpressed_member_id
のみ
###2. (②)index.phpにて、メッセージ一覧の投稿日時と削除リンクの間に、ハートマークといいね
の件数表示出来るように③④⑤を作って行く
表示イメージ:
###3. (③)index.phpにて、いいね
された件数を判別するために必要な情報を作り出す
テキストでは元々以下のような情報を作り出しているので、これに必要な情報を加えていく
メンバーのニックネーム | メンバーの写真のパス | postsテーブルの全項目 |
---|---|---|
members.name | members.picture | posts.* |
テキストの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を入れる
|いいねされたメッセージID|いいねされた件数| |:-:|:-:| |liked_post_id|COUNT(liked_post_id) AS li_cnt|
SQL
SELECT liked_post_id, COUNT(liked_post_id) AS li_cnt FROM likes GROUP BY liked_post_id) AS li
postsテーブルの全項目 | いいねされた件数 |
---|---|
posts.* | li_cnt |
postsを置き換える情報を作るためのSQL
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
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
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();
いいねしたメッセージID|
:-:|
liked_post_id|
SQL
SELECT liked_post_id FROM likes WHERE pressed_member_id=?
// ?には自身のIDとして$_SESSION['id']が入る
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に追加した処理
$likeAri = 0; // $likeAriは毎回初期化
for($i=0; $i<count($pressedMsg); $i++) {
if ($pressedMsg[$i]['liked_post_id'] == $post['id']) {
$likeAri = $post['id'];
break;
}
}
// 変数名のネーミングセンスが微妙過ぎる
index.phpに追加した処理
<?php if ($likeAri > 0) { ?>
<a class="like" style="color:#F33;" href="like_delete.php?id=<?php echo h($post['id']); ?>">♥</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']); ?>">♡</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
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();
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件ある例)
↓
いいねするとハートが赤くなって、数字が増える
↓
もう一度ハートマークを押すと、いいねが取り消されて色なし3件に戻る
※1メッセージに対して1人1回しかいいね出来ないようにしてある
振り返り
PHPの学習というよりは、SQLがメインだったかなという気がします。
試行錯誤している内にCOBOLっぽい感じになってきてしまった気がする(現職がCOBOLer)ので、もっとスマートに書けるようになりたいです。