Laravelで「いいね!」機能をつくる(ダウンロード可)

こんにちは。フリーランス・コンサルタント&エンジニアの 九保すこひ です。

さてさて、今回は少し前に公開した「【Laravel】ファイルのアップロード機能をつくる(ダウンロード可)」という記事と同じく「記事にしてなかったっけ❓❓」でお届けしたいと思います。

その内容はというと・・・

SNS時代によく見るようになった「いいね!」機能をつくる

というものです。

いいね!」といえば、フェイスブックで見たのが初めてですが、その後ホントにこの機能はどこでも見るようになりました。

そこで!

今回はLaravelでこの「いいね!」機能をつくってみます。
ぜひ楽しみながらやってみましょう❗

「生まれて初めて「いいね!
されたときの興奮は今でも覚えてます👍」

開発環境: Laravel 7.x

前提として

いいね!」するデータはなんでもいいのですが、今回はログイン機能をインストールすると作成されるusersテーブルで実装することにします。

そのため、まだインストールしていない方は「Laravel6.x以降でログイン機能をインストールする方法」を参考にしてテストデータを追加するところまでやっておいてください。

なお、テーブルはこのようになっていればOKです。

モデル&マイグレーションをつくる

では、「いいね!」されたデータを管理するlikesテーブルとそのモデルを作っていきましょう。

以下のコマンドを実行してください。

php artisan make:model Like -m

次に、作成されたマイグレーション・ファイルを開いて中身を以下のようにします。

/database/migrations/****_**_**_******_create_likes_table.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateLikesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('likes', function (Blueprint $table) {
            $table->id();
            $table->string('model')->comment('モデル名');
            $table->integer('parent_id')->comment('モデルのID');
            $table->string('ip')->comment('IPアドレス');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('likes');
    }
}

では、この状態でマイグレーションを実行しましょう。

php artisan migrate

するとテーブルはこうなります。

likesテーブルとのリレーションシップを設定する

次にusersテーブルからlikesテーブルのデータも取得できるように「1:多」のリレーションシップをつくっておきます。

// 省略

class User extends Authenticatable
{
    // 省略

    // Relationship
    public function likes() { // 👈 追加

        return $this->hasMany(\App\Like::class, 'parent_id', 'id')
            ->where('model', self::class);

    }

}

なお、重要なのはwhere()の部分です。
この例で言うとmodelフィールドが「App\User」ものだけ取得することになります。

ルートをつくる

続いてルートです。

Route::get('/like', 'LikeController@index'); // 👈 ブラウザでアクセスする
Route::get('/ajax/like/user_list', 'LikeController@user_list'); // 👈 ユーザー情報を取得
Route::post('/ajax/like', 'LikeController@like'); // 👈 いいね!データを追加

1行目は、ブラウザでアクセスするURLで、下の2つはAjax通信用になります。

コントローラーをつくる

次にコントローラーをつくります。
以下のコマンドを実行してください。

php artisan make:controller LikeController

そして中身を次のようにします。

/app/Http/Controllers/LikeController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class LikeController extends Controller
{
    public function index(Request $request) {

        return view('like.index')->with('ip', $request->ip());

    }

    public function user_list() {

        return $this->getUsers(); // 全ユーザーを取得

    }

    public function like(Request $request) {

        $request->validate([
            'user_id' => 'required|exists:users,id'
        ]);

        $result = false;
        $model = \App\User::class;
        $exists = \App\Like::where('model', $model)
            ->where('parent_id', $request->user_id)
            ->where('ip', $request->ip())
            ->exists();

        if(!$exists) {

            $like = new \App\Like();
            $like->model = $model;
            $like->parent_id = $request->user_id;
            $like->ip = $request->ip();
            $result = $like->save();

        }

        return [
            'result' => $result,
            'users' => $this->getUsers() // 全ユーザーを取得
        ];

    }

    private function getUsers() {

        return \App\User::with('likes')
            ->withCount('likes')
            ->get();

    }
}

それでは、中身をメソッドごとに説明していきます。

index()

ブラウザからアクセスされるときに実行されるメソッドです。
なお、ビューで現在アクセスしている人のIPアドレスが取得できるようにしています。

user_list()

Ajaxでユーザーデータを取得するためのメソッドです。

like()

このメソッドで「いいね!」データを追加することになります。

getUsers()

LikeController内でユーザーデータを取得する場所が2ヵ所あるのでひとつにまとめました。なお、private functionなのでこのクラスの中からしかアクセスすることはできません。

ビューをつくる

最後にビューです。

/resources/views/like/index.blade.php

<html>
<head>
    <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div id="app" class="container pt-4">
    <h1 class="mb-3">「いいね!」機能のサンプル</h1>
    <p class="bg-light p-3">「いいね!」できるのは、IPアドレスごとに1回までです。</p>
    <table class="table table-bordered">
        <thead class="bg-info text-white">
            <tr>
                <th>名前</th>
                <th class="text-nowrap">いいね!の回数</th>
                <th></th>
            </tr>
        </thead>
        <tbody>
            <!-- ユーザーリストを表示 ・・・ ① -->
            <tr v-for="u in users">
                <td class="w-100" v-text="u.name"></td>
                <td class="w-100" v-text="u.likes_count"></td>
                <td class="text-nowrap">
                    <!-- いいね!を実行するボタン ・・・ ② -->
                    <button
                        type="button"
                        class="btn btn-info"
                        :disabled="hasMyLike(u.likes)"
                        @click="addLike(u.id)">いいね!</button>
                </td>
            </tr>
        </tbody>
    </table>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.2/axios.min.js"></script>
<script>

    new Vue({
        el: '#app',
        data: {
            users: [],
            ip: '{{ $ip }}'
        },
        methods: {
            addLike(userId) { // いいね!を追加 ・・・ ①

                const url = '/ajax/like';
                const params = { user_id: userId };
                axios.post(url, params)
                    .then(response => {

                        if(response.data.result === true) { // 追加に成功したらデータを更新

                            this.users = response.data.users;

                        }

                    });

            },
            hasMyLike(likes) { // 自分のIPが含まれているかチェック ・・・ ②

                if(likes.length) {

                    for(let like of likes) {

                        if(like.ip === this.ip) {

                            return true;

                        }

                    }

                }

                return false;

            }
        },
        mounted() {

            axios.get('/ajax/like/user_list')
                .then(response => {

                    this.users = response.data;

                });

        }
    });

</script>
</body>
</html>

この中でやっているのは次のとおりです。

①ユーザーリストを表示

Vue.jsを使ってAjax通信で取得したユーザーデータをv-forでループさせ、1つずつ表示していくことになります。

②いいね!を実行するボタン

クリックされると、likesテーブルにデータが追加されることになります。

そしてさらに、:disabledを使ってすでに「いいね!」している場合はクリックができないようにしています。

③いいね!を追加

いいね!」ボタンがクリックされたときに実行されるコードです。

ここではAjaxで「いいね!」すべきユーザーIDを送信し、もし新規データが追加されたらusersデータを新しいものに置き換えることになります。

④自分のIPが含まれているかチェック

ここは、②で説明した:disabledの部分で使われる「すでに「いいね!」しているかどうか」をチェックするコードです。

テストしてみる

では実際にテストしてみましょう❗
まずブラウザで「http://*****/like」にアクセスします。

では、太郎さんと次郎さんの「いいね!」ボタンをクリックしてみます。

すると「いいね!」の回数が増えて、ボタンがクリックできなくなりました。

では、テーブルを見てみましょう。

太郎さん(ユーザーID: 1)次郎さん(ユーザーID: 2)のデータが存在していて、IPアドレスも保存されています。

では次に、太郎さんのIPアドレスを手動で変更します。

そして、ブラウザをリロードすると以下のように太郎さんの「いいね!」だけクリックできるようになります。

ではこれをクリックしてみましょう。

はい!
太郎さんの「いいね!」が2回になり、再度ボタンはクリックできなくなりました。

成功です😊✨

教材ソースコードをダウンロードする

今回実際に教材ソースコード一式を以下からダウンロードできます。

Laravelで「いいね!」機能をつくる

※ただし、マイグレーションはご自身で実行してください。

開発のご依頼お待ちしております
開発のご依頼はこちらから: お問い合わせ
どうぞよろしくお願いいたします! by 九保すこひ

おわりに

ということで、今回はLaravelを使って「いいね!」機能をつくってみました。

なお、以前私はEvaluationというパッケージを公開していますので、もしよりシンプルに実現したい方はそちらもチェックしてみてくださいね(Evaluationnで使えるのは「like」「dislike」「favorite」「remember」の4つです)

もしくは、今回の記事をじっくり勉強するのもありかもしれません👍

ではでは〜❗

「そういえば、当時はミクシィ
が人気でしたよね(まだアカウントあるかな❓)」

このエントリーをはてなブックマークに追加       follow us in feedly