「いいね！機能の実装方法」詳しく解説〜PHP/Laravelを使って

Hiroyukiです。

本日は、PHP/Laravelを使って、
####いいね！機能・いいね！ボタンを実装する方法！
について解説して行きます！

Twitterの影響か、みんな作ってみたい機能ですよね〜

完成イメージは下記の通りでーす！
####「いいね！を付ける」ボタンを押すと、「いいね！を外す」ボタンに切り替わって、
####右上に「いいね！の取得数」が表示される感じですねー！！
<img width="1051" alt="スクリーンショット 2019-09-22 9.45.55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/489124/b9160c95-262b-fc48-6e47-e12035eb15fd.png">

#どういう方針で作るの？
さて、今回は前提として、下記の画像のような
####ユーザ：コンテンツで、「１対多」の関係
があるようなサービスが既に作られている前提で、話を進めて行きま〜す！

<img width="695" alt="スクリーンショット 2019-09-22 8.04.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/489124/a1acaa25-0d90-f347-a3fc-fa144563ab57.png">

つまり、今回の「いいね！」機能では、各ユーザが各ムービー（コンテンツ）に「いいね！」をする形ですね。
いいね！機能の実装といっても、いろいろな方法があるとは思いますが
####ユーザとコンテンツの間に、いいね！機能を持たせる「中間テーブル」を作成する方法で解説したいと思います。

僕が作っているのが、下記サイトの、動画を使ったSNSサービスみたいなものなので、
コンテンツは 「movies(動画)」 となっていますが、
####ツイッタークローンなど作成の場合も、実装方法は全く同じだと思いますので、
####是非ぜひ参考にしてみてくださーい＾＾

※Twitterクローンの場合は、
 コンテンツが「つぶやき（tweets,micropostsなど）」に変わるだけですね！

####ボクのオリジナルサービス　【いいね！機能実装済み】
####●YouTubeまとめ × コミュニケーション
####http://youtubematome.herokuapp.com


#いいね！テーブルの作成

では早速作って行きまっしょ〜

テーブルの名前は何でもOKですが、「favorites」テーブルとかで、いいでしょう！

```php
$ php artisan make:migration create_favorites_table --create=favorites
```
で、生成されるのが、下記の通りのデータです！

migrations/年月日時_create_favorites_table.php の up() と down()

```php
    public function up()
    {
        Schema::create('favorites', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('user_id')->unsigned()->index();
            $table->integer('movie_id')->unsigned()->index();
            $table->timestamps();

        $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
        $table->foreign('movie_id')->references('id')->on('movies')->onDelete('cascade');

        $table->unique(['user_id','movie_id']);
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('favorites');
    }
}
```
マイグレーションを実行します。

```php
$ php artisan migrate
```

#モデルに追記していく
中間テーブルのための「Model」などは作らずに進めて行きますが
その代わりに、Userモデル等を少しイジらないといけません！

User.php（抜粋）

```php3
    public function favorites()
    {
        return $this->belongsToMany(Movie::class, 'favorites', 'user_id', 'movie_id')->withTimestamps();
    }

    public function favorite($movieId)
    {
        $exist = $this->is_favorite($movieId);

        if($exist){
            return false;
        }else{
            $this->favorites()->attach($movieId);
            return true;
        }
    }

    public function unfavorite($movieId)
    {
        $exist = $this->is_favorite($movieId);

        if($exist){
            $this->favorites()->detach($movieId);
            return true;
        }else{
            return false;
        }
    }

    public function is_favorite($movieId)
    {
        return $this->favorites()->where('movie_id',$movieId)->exists();
    }
```
####favorites()関数　→　Userクラスが、favoritesテーブルを通して、Movieクラスと繋がっている
####（それぞれのidで関連づけられている）
ということを表しています。
更に

####is_favorite()関数　→　既に「いいね！」しているか？

を判定するための関数も追記していますっ！
そして、

####favorite()関数　→　「いいね！」を付ける！
####unfavorite()関数　→　「いいね！」を外す！

という、それぞれの処理が行われるというやり方ですな。


そしてそして、、、
####「いいね！」の数を表示させたい人は、コンテンツのモデル（ボクの場合はMovieモデル）もイジりませう〜
コンテンツのモデルMovie.php（抜粋）に以下を追記する

```php
public function favorite_users()
    {
            return $this->belongsToMany(User::class,'favorites','movie_id','user_id')->withTimestamps();
    }
```
これで、コンテンツに「いいね！」しているユーザーをサクッと抜き出すことができます！！
カンタンですね〜＾＾

#ルーティング
web.php

```php
Route::group(['middleware'=>'auth'],function(){
    Route::group(['prefix'=>'movies/{id}'],function(){
       Route::post('favorite','FavoriteController@store')->name('favorites.favorite');
       Route::delete('unfavorite','FavoriteController@destroy')->name('favorites.unfavorite');
    });
});
```
該当するidを持っているmovieに対して、favorite(いいね！付ける)/unfavorite(いいね！外す)の処理がされるように
ルーティングを設定するわけです。

#コントローラーを実装

まず、いいね！専用コントローラーを作っちゃいましょ〜

```php
$ php artisan make:controller FavoriteController
```
んで、生成できたら、その中身を追記します。

FavoriteController.php の store と destroy

```php
namespace App\Http\Controllers;

use Illuminate\Http\Request;

class FavoriteController extends Controller
{
    public function store(Request $request, $id)
    {
            \Auth::user()->favorite($id);
            return back();
    }

    public function destroy($id)
    {
            \Auth::user()->unfavorite($id);
            return back();
    }
}
```
#いいね！ボタンの実装

いよいよ完成が近づいてきましたね〜
viewの任意の位置に、「いいね！」ボタンを作成しましょ！

view

```php
@if (Auth::id() != $user->id)

    @if (Auth::user()->is_favorite($movie->id))

        {!! Form::open(['route' => ['favorites.unfavorite', $movie->id], 'method' => 'delete']) !!}
            {!! Form::submit('いいね！を外す', ['class' => "button btn btn-warning"]) !!}
        {!! Form::close() !!}

    @else

        {!! Form::open(['route' => ['favorites.favorite', $movie->id]]) !!}
            {!! Form::submit('いいね！を付ける', ['class' => "button btn btn-success"]) !!}
        {!! Form::close() !!}

    @endif

@endif
```
解説：
下記の判定後、それぞれのボタンを表示しています。

####・自分が閲覧しているユーザが自分自身ではないか？
####・自分が既にこのコンテンツを「いいね！」しているかどうか？

つまり、判定を要約すると、

####閲覧しているユーザが自分自身でなく、かつ、既に「いいね！」済みの時　→　「いいね！を外す」ボタンを表示
####閲覧しているユーザが自分自身でなく、かつ、まだ「いいね！」済みではない時　→　「いいね！を付ける」ボタンを表示

が、それぞれ表示されます！！
これが上手く実装できて表示された時は、かなり嬉しいですね〜

####初学者のボクは跳び上がって喜びました（笑）

#いいね！取得数の表示

いいね！の数を表示たい方は、実装方法を見ていきませう〜

ここで、さっきMovie（皆さんのコンテンツの）モデルに
####favorite_users()
を書き込んだのが効いてきます。

いいね！の数を表示させるviewに情報を渡すコントローラーに、下記を追記します。

対象のコントローラー

```php
class UsersController extends Controller
{
    public function index()
    {
        $count_favorite_users = $movie->favorite_users()->count();

        $data=[
               'count_favorite_users'=>$count_favorite_users,
              ];

        return view('いいね！の数を表示させるview名',$data
        );
    }
```

では最後！

いいね！数の表示部分の実装ですー

viewに追記

```php
<div class="text-right mb-2">いいね！
     <span class="badge badge-pill badge-success">{{ $count_favorite_users }}</span>
</div>
```

#実装後どんな感じになるの？
####はい、完成です！

今一度、完成後の様子を見たい方は、
いいね！機能実装済みのサイトを公開してますので、是非下記からご覧下さいね〜

####ボクのオリジナルサービス　【いいね！機能実装済み】
####●YouTubeまとめ × コミュニケーション
####http://youtubematome.herokuapp.com
<img width="1399" alt="スクリーンショット 2019-09-17 8.05.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/489124/bb6f6c2d-dba0-389d-2be3-ca51f7a4d768.png">

#次回は・・・
今回は、いいね！機能と、各コンテンツの「いいね！」数の表示のみでしたが、
####次回は、ユーザが「いいね！」をゲットした総数（各コンテンツの「いいね！」数をトータルした合計数）
を表示させる方法を解説したいと思っています（これがまたまた苦労しました、、、汗）

ではまた、Hiroyukiでした！！！