0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【PHP / Laravel】最も簡単ないいね機能を実装する

Last updated at Posted at 2025-03-29

🎒 はじめに

超シンプルないいね機能をLaravelで実装してみました.

🎒 自己紹介

初めまして.趣味でweb開発を勉強している273*(ツナサンド) / Kei.と申します.フルスタック開発やツール制作を行なっています.まだまだ初心者です.

テーブル作成

  • 中間テーブルを作成します.user,postテーブルは事前に用意しておきましょう.
  • php artisan make:migration create_post_likes_table
  • yyyy_mm_dd_hhmmss_create_likes_table.php
public function up(): void
{
    Schema::create('likes', function (Blueprint $table) {
        // constrainedの第一引数は参照するテーブル名.
        // 何も指定しない場合は外部キー(foreignId)から自動で推測される.
        $table->foreignId('user_id')->constrained("users")->onDelete('cascade');
        $table->foreignId('post_id')->constrained("posts")->onDelete('cascade');
        // 主キーをuser_idとpost_idの組み合わせにする
        $table->primary(['user_id', 'post_id']);
        $table->timestamps();
    });
}

モデルの作成,追加

  • php artisan make:model Like
  • Like.php
// リレーション (Like belongs to a Post)
public function post()
{
	return $this->belongsTo(Post::class);
}

// リレーション (Like belongs to a User)
public function user()
{
	return $this->belongsTo(User::class);
}
  • User.php / Post.php(追加)
public function likes()
{
	// User / Post has many Likes
	return $this->hasMany(Like::class);
}

ルーティング

  • web.php
Route::post('/posts/{postId}/like', [LikeController::class, 'likePost'])->middleware("auth");

いいね登録・削除処理

  • LikeController.php
 public function likePost(Post $post)
{

    // ログインユーザーのidを取得
    $user_id = Auth::id();

    // ログインユーザーがその投稿をいいねしているレコードを取得
    $liked_post = $post->likes()->where('user_id', $user_id);

    // 既に「いいね」しているか確認
    if (!$liked_post->exists()) {

        //「いいね」していない場合は,likesテーブルにレコードを追加
        $like = new Like();
        $like->user_id = $user_id;
        $like->post_id = $post->id;
        $like->save();
    } else {
        // 既に「いいね」をしていた場合は,likesテーブルからレコードを削除     
        $liked_post->delete();
    }

    // いいねの数を取得
    $likes_count = $post->likes->count();

    
    $param = [
        'likes_count' => $likes_count, // いいねの数
    ];

    // フロントにいいねの数を返す
    return response()->json($param);
}

いいねボタンの挙動を実装

resourcesディレクトリにlike.jsを作成
流れ:全てのいいねボタンを取得,いいねボタンを押されたら,バックエンドにいいね処理を行うように送信.処理が成功したら,非同期でいいね数とアイコンを変更.

  • resources/like.js
// 非同期でいいね機能を実装

// 全てのいいねボタン(ハートアイコン)の要素を取得
const likeBtns = document.querySelectorAll(".like-btn");

likeBtns.forEach((likeBtn) => {
    // どれかのいいねボタンがクリックされた時の処理
    likeBtn.addEventListener("click", async (e) => {
        // クリックされたいいねボタンのid(post id)を取得
        const postId = e.target.id; 

        // /posts/{postId}/likeにPOSTリクエストを送信
        await fetch(`/posts/${postId}/like`, {
            method: "POST", // リクエストメソッドはPOST
            headers: {
                //Content-Typeでサーバーに送るデータの種類を伝える。今回はapplication/json
                "Content-Type": "application/json",
                //csrfトークンを付与
                "X-CSRF-TOKEN": document
                    .querySelector('meta[name="csrf-token"]')
                    .getAttribute("content"),
            },
        })
            .then((res) => res.json()) // レスポンスをJSON形式に変換;
            .then((data) => {
                // いいねの数を更新
                e.target.nextElementSibling.innerHTML = data.likesCount;
                
                // いいねの状態によってハートアイコンの色を変更
                if (e.target.classList.contains("text-pink-500")) {
                    e.target.classList.remove("text-pink-500");
                    e.target.setAttribute("name", "heart-outline");
                } else {
                    e.target.classList.add("text-pink-500");
                    e.target.setAttribute("name", "heart");
                }
            })
             // 失敗した場合はアラートを表示
            .catch(() => alert("いいね処理が失敗しました"));
    });
});

  • app.js
import "./like"; // 追加

いいねボタンの作成

<!-- bladeファイルのheadタグ -->
<head>
    <meta charset="utf-8">
    <title>Blog</title>
    <!-- Fonts -->
    <link href="https://fonts.googleapis.com/css?family=Nunito:200,600" rel="stylesheet">

	<!-- アイコンの読み込み -->
	<meta name="csrf-token" content="{{ csrf_token() }}">
    <script type="module" src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.esm.js"></script>
    <script nomodule src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.js"></script>
</head>

<!--いいねボタンの作成 -->

<div class="flex items-center gap-3">
    <h2 class='title text-xl text-blue-600 font-bold'>
	    <a href="/posts/{{ $post->id }}">{{ $post->title }}</a>
    </h2>
    @auth
    <!--その投稿がいいねしているか判定 -->
    @if (Auth::user()->likes()->where('post_id', $post->id)->exists())
    <ion-icon name="heart" class="like-btn cursor-pointer text-pink-500" id={{$post->id}}></ion-icon>
    @else
    <ion-icon name="heart-outline" class="like-btn cursor-pointer" id={{$post->id}}></ion-icon>
    @endif
    <p class="count-num">{{$post->likes->count()}}</p>
    @endauth
</div>

🎒 最後に

Laravelは非常に扱いやすいフレームワークですね.今後も触っていきたいと思います.最後まで読んでいただきありがとうございました!

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?