😁

PHPとajax(jquery)でいいね機能実装

2023/09/30に公開

学習日記 20230930
今回はタイトルの件をまとめてみました。
ある投稿サービスを作成している人間です。(開発の実務は未経験で、学習中の人間です)
※使用しているPHPフレームワークは"パーフェクトPHP"という書籍で扱っている
独自のフレームワークになります。
なるべく上記の独自な書き方の箇所は直しますが、キリがないと判断した場合、
処理全体のイメージだけでもつかんでいただければと思います、

使用するもの

今回は下記の環境で実施します。

  • PHP 8.2
  • jquery 3.6.0
  • MySQL(phpmyadmin)
  • fontawesome
  • レンタルサーバ上

処理の流れ

  1. ハートアイコンのクリックでイベント発火
  2. クリックした要素をthisで取得、付随するカスタムデータ属性の値も取得
  3. ajaxの処理
  4. 取得した値をphpファイルに渡す
  5. ajaxから取得した値とSESSIONから取得した値のバリデーション
  6. どちらも通ったなら、既にいいねしているか判別
  7. 5の結果により、DBへの追加か削除も処理をする。
  8. 処理結果をレスポンス用データ変数に格納
  9. json形式でajaxに返却
  10. ajax側でレスポンスを受け取る
  11. レスポンスの中身にある"追加"か"削除"かを表すデータを取得して、処理を分ける
  12. 追加、削除したかによって、htmlにおけるクラスのつけ外しをjqueryで行う
  13. レスポンスの中身にあるいいね数データも取得して、html側に反映
  14. html側では、いいねしているかといいね数を既に表示する処理をphpで記述する
    ※(14はクリックイベントとは別で常時表示する際の処理)
  15. css適用

使用するテーブル

いいねのデータを格納する際のテーブルを作成します。
投稿に対し、

  • "どの投稿に対して(投稿記事のID)"
  • "誰がいいねしたのか(ユーザID)
    が分かればいいので下記のようなテーブルを作成します。

処理の流れ(コード付き)

  1. ハートアイコンのクリックでイベント発火
  2. クリックした要素をthisで取得、付随するカスタムデータ属性の値も取得
    ※like-btnが同じページに複数存在するので、クリックされたlike-btnのみを
    表現するためにvar $this = $(this);としています。
list.html
<i class="like-btn fa-heart far" data-articleid = <記事のID></i>
->この場合、html上に黒枠のハートアイコンが表示されるはずです。
ajax.js
$(function() {

	$('.like-btn').on('click', function() {

		//$(this)でクリックしたもののみのクラス?を取得
		var $this = $(this);
		var article_id = $this.data('articleid');
	});
});
  1. ajaxの処理
ajax.js
$(function() {

	$('.like-btn').on('click', function() {

		//$(this)でクリックしたもののみのクラス?を取得
		var $this = $(this);
		var span = $this.next();
		var article_id = $this.data('articleid');
ここから追記
		$.ajax({
			url: "URL", // phpへのURLを指定
			type: "POST", // GET,POSTなどを指定
			dataType: "json",
			data: { // データを指定
				article_id : article_id,
			}
		}).done(function (data) {
			// 通信成功時のコールバック処理
			console.log('Ajax Successe');
		
		}).fail(function (data) {
			// 通信失敗時のコールバック処理
			console.log('fail');
			console.log(data);
		
		}).always(function (data) {
			// 常に実行する処理
			console.log('always');
			console.log(data);
			// alert(json);
		
		});
	});
});
	
  1. ajaxから取得した値とSESSIONから取得した値のバリデーション
  2. どちらも通ったなら、既にいいねしているか判別
  3. 5の結果により、DBへの追加か削除も処理をする。
  4. 処理結果をレスポンス用データ変数に格納
  5. json形式でajaxに返却
ajax.php
<?php


class ApiController extends Controller
{
	public $code;

	public function ajaxAction()
	{
		//投稿記事IDの取得
		$article_id = !empty($_POST['article_id']) ? $_POST['article_id'] : null;

		try {

			if (empty($article_id)) 
				throw new Exception('error');

			//セッションからログインユーザ情報の取得
			$user = !empty($this->session->get('user')) ? $this->session->get('user') : throw new Exception('user none');

			//バリデーションは良きにやってください。
			
			//6.いいねをすでにしているか
			$isgood = $this->db_manager->get('Good')->isGood($user['id'], $article_id) ? true : false;
			
			//7.していないなら削除、しているなら追加
			if($isgood){
				$this->db_manager->get('Good')->delete($user['id'], $article_id);				
			}else{
				$this->db_manager->get('Good')->insert($user['id'], $article_id);
			}

			//8.レスポンス用のデータ作成
			$GoodCount = $this->db_manager->get('Good')->goodCount($article_id);
			$res['isgood'] = $isgood;
			$res['goodCount'] =  $GoodCount['cnt'];

			$this->code = $res;

		} catch (Exception $e){

			$this->code = array('error' => $e->getMessage());
		}


		$json = json_encode($this->code);

		//9.Json形式で返却
		header('Content-type: application/json; charset=utf-8');
		echo $json;
		exit;
	}
}
  1. レスポンスの中身にある"追加"か"削除"かを表すデータを取得して、処理を分ける
  2. 追加、削除したかによって、htmlにおけるクラスのつけ外しをjqueryで行う
  3. レスポンスの中身にあるいいね数データも取得して、html側に反映

この時、phpから返却されるデータは下記になります。
{['isgood'] => trueかfalse, ['goodCount'] => いいねの数}

list.html
<i class="like-btn fa-heart far" data-articleid = <記事のID></i>
ajax.js
$(function() {

	$('.like-btn').on('click', function() {

		//$(this)でクリックしたもののみのクラス?を取得
		var $this = $(this);
		var span = $this.next();
		var article_id = $this.data('articleid');

		$.ajax({
			url: "URL", // phpへのURLを指定
			type: "POST", // GET,POSTなどを指定
			dataType: "json",
			data: { // データを指定
				article_id : article_id,
			}
		}).done(function (data) {
			// 通信成功時のコールバック処理
			console.log('Ajax Successe');
ここから追記
			//11,12.レスポンスがtrue(いいねしていた)である時、ハートのアイコンを白地にする。
			if(data['isgood']){
				$this.removeClass('active fas');
				$this.addClass('far');
				span.removeClass('active');
			} else {
				$this.removeClass('far');
				$this.addClass('active fas');
				span.addClass('active');
			}
			//13.同時に取得してきたいいね数をviewに反映する。
			span.text(data['goodCount']);
ここまで

		
		}).fail(function (data) {
			// 通信失敗時のコールバック処理
			console.log('fail');
			console.log(data);
		
		}).always(function (data) {
			// 常に実行する処理
			console.log('always');
			console.log(data);
			// alert(json);
		
		});

	});

});
  1. html側では、いいねしているかといいね数を既に表示する処理をphpで記述する
    ※(14はクリックイベントとは別で常時表示する際の処理)
    このコードは冒頭で触れた独自フレームワークの書き方が多いです。
    $articleというものは、このビューであるlist.phpに渡す前に
    コントローラ側でデータベースから取得してきたものを連想配列に整形したものです。
list.php(先ほどのlist.htmlの書き換え)
<i class="like-btn fa-heart <?php $article['isgood'] ? print ' active fas' : print ' far'; ?>"
	data-articleid = <?php echo $article['id']; ?>>			
</i>
<span class="<?php if($article['isgood']) echo ' active'; ?>">
	<?php echo $article['goodcnt']; ?>
</span>
$articleの中身
array(10) {
    ["id"]=>
    int(75)
    ["user_id"]=>
    int(6)
    ["name"]=>
    string(4) "hoge"
    ["icon_image_file"]=>
    string(0) ""
    ["create_at"]=>
    string(19) "2023-09-22 00:53:31"
    ["image"]=>
    string(28) "hogehogehogehoghoge.jpg"
    ["isgood"]=>
    bool(false)
    ["goodcnt"]=>
    int(1)
  }
  1. css適用
style.css
.like-btn {
  cursor: pointer;
}
.active{
  color: #f60909;
}

成功イメージ

いいね前

いいね後

実装を通して

1週間で実装しましたが、たまたま参考になる資料を見つけたからでした。
参考資料の方も言っていましたが、詰まった際はメモ帳か何かに
やろうとしている処理を、事細かに、段階を踏んで、書いてみることが大事だと思います。
私も学習日記たるものをなるべくつけるようにしていますが、
日本語がめちゃくちゃでもとりあえず書いてます。
そうすれば、おのずと、見えてくるものがあるはずです。
未経験で詰まると、精神的にきついですが、めげずにやっていこうと思います。
今後はXのようにいいねのアニメーションもつけてみたいと思っています。

参考資料

https://qiita.com/kanasann1106/items/4ea0675afde639e6d540
この方の資料のおかげで大変はかどりました。

Discussion