質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.59%

いいね機能の実装(ログインユーザーのみ1人1回)

解決済

回答 4

投稿

  • 評価
  • クリップ 1
  • VIEW 1,872

mango

score 17

目標

いいね機能の実装を試みています。
ログインユーザーのみいいね!することが可能で、1人1回、いいね!ボタンをクリックすると+1で値が追加され、再びクリックすると-1されるような処理をしていきたいです。

現状(問題点)

現在、ログイン機能と投稿機能は実装できていて、いいね機能が途中段階です。

いいね機能に関しては、クリックすると+1されてpostsテーブルのlikes_countの値も同様に変化し、値を返してくれるというところまではできています。
ですが、ページをリロードするとボタンのクリックが消えて再びいいね!できてしまうという状況です。

具体的にどのようにすれば、目標のようないいね機能になるのでしょうか?

mysql> desc posts;
+-------------+----------+------+-----+---------+-------------------+
| Field       | Type     | Null | Key | Default | Extra             |
+-------------+----------+------+-----+---------+-------------------+
| id          | int(11)  | NO   | PRI | NULL    | auto_increment    |
| file_name   | text     | NO   |     | NULL    |                   |
| extension   | text     | NO   |     | NULL    |                   |
| likes_count | int(11)  | YES  |     | 0       | DEFAULT_GENERATED |
| created     | datetime | YES  |     | NULL    |                   |
| modified    | datetime | YES  |     | NULL    |                   |
+-------------+----------+------+-----+---------+-------------------+
<?php

ini_set('display_errors', 1);

define('MAX_FILE_SIZE', 1 * 1024 * 1024); //1MB
define('THUMBNAIL_WIDTH', 400);
define('IMAGES_DIR', __DIR__ . '/images');
define('THUMBNAIL_DIR', __DIR__ . '/thumbs');

if (!function_exists('imagecreatetruecolor')) {
  echo "GD not installed";
  exit;
}


require 'ImageUploader.php';

$uploader = new \MyApp\ImageUploader();

if($_SERVER['REQUEST_METHOD'] === 'POST') {
  $uploader->upload();
}

list($success, $error) = $uploader->getResults();

$images = $uploader->getImages();


require_once(__DIR__ . '/Login/config/config.php');

 ?>


 <!DOCTYPE html>
 <html lang="ja">
   <head>
     <meta charset="utf-8">
     <title>**</title>
     <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.4.1/css/all.css" integrity="sha384-5sAR7xN1Nv6T6+dT2mhtzEpVJvfS3NScPQTrOxhwjIuvcA67KV2R5Jz6kr4abQsz" crossorigin="anonymous">
     <link rel="stylesheet" href="styles.css">
   </head>

   <body>

     <header class="bg">
       <div class="container">
         <h1>****</h1>
       </div>
       <div class="logined">
         <p class="mypage"><a href="mypage.php"><i class="fas fa-user-circle"> My Page</i></a></p>
       </div>
     </header>


     <!-- ** -->
     <section class="feature">
       <div class="container">
         <h1><a href="">**</a></h1>
       </div>
     </section>

     <section class="images">
       <ul class="img_row">
         <?php
           $sql = "SELECT * FROM posts ORDER BY id desc;";
           $stmt = $pdo->prepare($sql);
           $stmt -> execute();
           while ($row = $stmt -> fetch(\PDO::FETCH_ASSOC)):
          ?>
         <li>
           <?php
           echo ("<a href='/images/$row[file_name]'>");
           echo ("<img src='/thumbs/$row[file_name]' class='img' id ='$row[id]'></a>");
           echo ("<div class='heart icon' id='icon_$row[id]'></div>");
           echo ("<div class='likes_count' id='likes_count_$row[id]'>  $row[likes_count] </div>");
           ?>
         </li>
         <?php endwhile; ?>
       </ul>
     </section>

   <footer class="bg">
     <p>&***</p>
   </footer>

       <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
       <script>
       $(function() {
         'use strict';

         $( '.icon' ).on( 'click', function() {
            var $_t = $( this );
            $_t.css( 'color', 'red' );
            $.post( 'Countup.php', {
                id: $_t.parent().find( 'img' ).attr( 'id' )
            }, function( data ) {
                $_t.parent().find( '.likes_count' ).text( data );
            } );
          } );

       });


       </script>
   </body>
 </html>
<?php

require_once(__DIR__ . '/Login/config/config.php');
require_once(__DIR__ . '/Like.php');

$likeApp = new \MyApp\Like();


if ($_SERVER['REQUEST_METHOD'] === 'POST') {
  try {

    $res = $likeApp->post();
    echo $res;

  } catch (Exception $e) {
    header($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error', true, 500);
    echo $e->getMessage();
    exit;
  }
}


?>
<?php

namespace MyApp;

class Like {

    private $pdo;

    public function __construct() {
        try {
            $dsn = "mysql:dbhost=localhost;dbname=*****";
            $username = "***";
            $password = "***";
            $this->pdo = new \PDO($dsn, $username, $password);
            $this->pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);

        } catch (\PDOException $e) {
            echo $e->getMessage();
            exit;
        }
    }

    public function post() {

        if (!isset($_POST['id'])) {
            throw new \Exception('[update] id not set!');
        }

        $id = $_POST['id'];

        $this->pdo->beginTransaction();

    $sql = "UPDATE posts set likes_count = likes_count+1 where id = :id;";
    $stmt = $this->pdo->prepare($sql);
    $stmt->bindValue(":id", $id, \PDO::PARAM_INT);
    $stmt->execute();

    $sql = "SELECT likes_count from posts where id = :id;";
    $stmt = $this->pdo->prepare($sql);
    $stmt->bindValue(":id", $id, \PDO::PARAM_INT);
    $stmt->execute();
        $result = $stmt->fetch(\PDO::FETCH_ASSOC);

        $this->pdo->commit();

        echo $result['likes_count'];

    }
}

?>
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

checkベストアンサー

+1

この記事にこのユーザーがいいねしたっていう情報が足りないですね。

例としては
posts_like<-テーブル名
テーブル中身
post_id(記事id)
user_id(いいねしたユーザーID)
っていうテーブル作っていいねされたらここにデータを追加する(&データあった場合は消す)
ってやればいいかと(いいね数はこのテーブルから求めることができるのでlikes_countは不要になるかもしれません)

※DB設計ちゃんとしないとデータ数膨れ上がるのであくまで例えです

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/29 18:20

    回答ありがとうございます!
    このテーブルの場合、仮に「いいね」された時、データの流れはどのようになるのでしょうか?

    キャンセル

  • 2018/11/29 19:40

    post_idとuser_idでユニークにしておくとして

    いいねされた際
    その1
    ・テーブルに(post_id, user_idでチェックした際)データが有ればデータを削除する
    ・テーブルに(post_id, user_idでチェックした際)データがなければデータをを追加する

    その2
    ・テーブルにデータをを追加する
    ・重複エラーが出た際はデータを消す

    キャンセル

+1

その要件でしたら、カウント値ではなく、ユーザidを保持し、「いいね」の数は、ページ表示時にcount()で表示するような動作およびテーブルに再設計する必要があると思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/29 18:14

    回答ありがとうございます!
    postsテーブルにユーザーID数をカウントするカラムを作り、そのデータを表示するということでしょうか?

    キャンセル

  • 2018/11/29 18:46

    他の回答見てください。
    パクリになりますが
    tableとしてpost_favを作りそこにpostidとuseridの2カラムを持ちます。
    で、postidが1にuseridが234さんがいいねしたらこのペアをインサート。いいねを取り消したらデリートします。
    表示のときは、select count(*) from post_fav where postid =:idといったクエリを発行して、その値を表示させるイメージです

    キャンセル

+1

同じ発言に複数のユーザーがいいねしたり、いいねを取り消す機能になるでしょうから、
発言ID(発言毎の連番)とユーザーIDをprimary keyとした別テーブルが必要です。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/29 18:12

    回答ありがとうございます!
    「発言ID(発言毎の連番)とユーザーIDをprimary keyとした別テーブルが必要です。」
    →抽象度が高いので、もう少し具体的な関係性を教えていただけるとありがたいです!

    キャンセル

+1

「いいねしたユーザ」をMySQL DBに保存していないのが問題ですね。
考え方的には二通りあります。

  • ユーザアカウントを管理しているDBに「いいね」したページの識別子を入力
  • 「いいね」されるページ側のDBに「いいねしたユーザID一覧」を入力

ページ読み込み時に、いいね済かを照合すればいいでしょう。
後者は「いいねしたユーザIDの数」が「いいね数」になるので、管理面で都合がよいかもしれません。


前質問でyambejpさんからのアドバイスがありますね。
https://teratail.com/questions/160948

Re: mango さん

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/29 18:09

    回答ありがとうございます!
    いいねしたページとされたページとはどういうことでしょうか?

    キャンセル

  • 2018/11/29 20:35

    主体が違うだけで、同じ意味です。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.59%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る