バックエンドとフロントエンドを行き来するWEBプログラマ―のメモ帳

WEBプログラマ―。バックエンドはPHP, MySQL, CentOS系, フロントエンドはJavaScript, jQuery, HTML, CSSで仕事してます。

Laravelで、いいねした写真の一覧を表示するには

f:id:mashiro_ruka:20190625011942p:plain
写真素材:
pixabay.com


上のようないいねをした画像を取得して、表示する部分について解説します。

取りたい情報

・写真がいいねされた数
・写真のコメントの数

3つのテーブルを用意

まず、3つのテーブルを使用します。

ユーザーテーブル、写真テーブル、いいねテーブル

カラムは必要なところだけをかくと
●ユーザーテーブル
・id (これが他のテーブルと紐づくuser_id)
・他、nameなどのカラム

●写真テーブル
・id (これが他のテーブルと紐づくphoto_id)
・user_id
・他、titleなどのカラム

●いいねテーブル
・user_id (これが他のテーブルと紐づくuser_id)
・photo_id
※user_idとphoto_idは組み合わせが重複しないように複合キーにする。
マイグレーションファイル一部

<?php
...
Schema::create('skill_user', function (Blueprint $table) {
            $table->unsignedInteger('skill_id');
            $table->unsignedInteger('user_id');
            $table->primary(['skill_id', 'user_id']);//複合キー
...

SQLからデータを取得

例えば、ユーザー1が、いいねをした写真一覧を取得するということなので、
内部結合で表すと

 INNAR JOIN
SELECT photos.id FROM photos INNER JOIN favorites ON photos.id = favorites.photo_id and favorites.user_id = $user_id;

Laravelでは

<?php
        $photos = DB::table('photos')
         ->join('favorites', 'photos.id', '=', 'favorites.photo_id')
         ->where('favorites.user_id', '=', $user_id)
         ->get();

        return view('mypage')->with([
         'photos' => $photos,
         ...
      ]);

となりますが、
これだと、viewの方で、photosをforeachで回したとき、
子要素のphotoでリレーションを使う時にエラーが出ました。
まぁ…配列のデータしか取れてないことが原因なわけですが…

hasManyThroughを使おう

よってそのため、以下のように【hasManyThrough】を使って、3つのテーブルをまたぐリレーションを行います。

<?php
...
class User extends Authenticatable{

    //~省略~

    public function join_favorites_photos()
    {
        return $this->hasManyThrough(
            'App\Photo', //リレーションして取りたいテーブル「photos」
            'App\Favorite', //経由するテーブル「favorites」
            'user_id', //favoritesテーブルをusersテーブルと結ぶための外部キー
            'id', // photosテーブルの外部キー
            null, // usersテーブルのローカルキー
            'photo_id' //favoritesとphotosを結ぶために使うキー
        );
    }
}

リレーション先テーブル「posts」

rolesテーブルのidとmembersテーブルのroles_idを結合
membersテーブルのidとPostsテーブルのmembers_idを結合

bladeでいいねの数とコメントの数を表示する部分を作成

これをすると、2つのテーブルで行うhasManyなどのリレーションと同じように
子要素のリレーションもビューでデータを取得できます。
実際に、いいねの数と、コメントの数をビューで表示してみましょう。

<?php
    // いいねの数
    $photo->favorites->count();
    // コメントの数
    $photo->comments->count();

ビューの部分

<div class="gallery flex border mb-4 p-2">
  @foreach ($photos as $photo)
  <div class="photo border mb-4 p-2">
    <a href="/photo/{{ $photo->id }}">
      <div class="img_cover">
        <img src="/storage/thumbnail_images/{{ $photo->image_name }}" />
      </div>
    </a>
    <div class="flex space-between bottom-imginfo">
      <div>
        <img src="/img/heart-regular.svg" width="20">
        <u><b>{{ $photo->favorites->count() }}</b></u> ←ここでしっかりデータが取得できる
        <img src="/img/comment-dots-regular.svg" width="20">
        <u><b>{{ $photo->comments->count() }}</b></u> ←ここでしっかりデータが取得できる
      </div>
      <div>
        <form method="POST" action="{{ action('FavoriteController@destroy_redirect', ['photo_id' => $photo->id]) }}">
          @csrf
          @if ($page_kind === 'mypage')
          <button type="button" class="btn btn-primary btn-sm">編集</button>
          @endif
          <button type="submit" class="btn btn-danger btn-sm">
            @if ($page_kind === 'favorite')
            解除
            @else
            削除
            @endif
          </button>
        </form>
      </div>
    </div>
  </div>
  @endforeach
</div>

これで完成です。

参考サイト
qiita.com

php-junkie.net