前回は、動画登録機能の全般を学習しました。
今回は、カラムを後から追加する方法・フォロー機能について学んでいきます。

カラムを後から追加することができれば、アプリケーションの表示や機能を、後からどんどん拡張して行くことが可能です。

また、SNS機能の肝である「フォロー機能」も実装していきます。
これが実装できれば、Laravelを使ってTwitterクローン(Twitterに似せたアプリケーション)も作れる実力が付きます。

多対多の関係など少し複雑な部分もありますが、一通りの流れが理解できれば大きな実力が付くはずですので、是非前向きに取り組んでみて下さい。

●今回のキーポイント

  • カラムの追加
  • カラム追加に伴う作業
  • フォロー機能
  • 多対多の関係
  • 中間テーブルとは?
  • フォロー人数の表示
  • フォローボタンの条件分岐
  • 共通部分の切り出し

この記事の目次 [表示]

前回の内容はこちら

https://yu-nocode.com/entry/laravel-quest-4/

カラムの追加

一度usersテーブルやmoviesテーブルのマイグレーションを実行した後で、それぞれのテーブルにカラムを追加したいということもあると思います。

カラムの追加方法について学習していきましょう。
今回は、ユーザがどのような動画一覧を持っているのかを示す「チャンネル名」を追加して
更にその「チャンネル名」(と合わせてユーザの名前も)変更・表示できる機能を追加していきましょう。

マイグレーション

カラムを追加するためのマイグレーションファイルを作っていきます。
マイグレーションファイルの名前は、カラムを追加することが分かりやすいような名前とするためadd_channel_to_users_table という名前にしましょう。
--table=users はどのテーブルに追加するかを決めている記述です。

ターミナル

$ php artisan make:migration add_channel_to_users_table --table=users

マイグレーションファイルが作成されると思いますので、中身を記述していきましょう。
今回は、up()もdown()もどちらの関数も記述していきます。

laravel-quest > database > migrations > xxxx_add_channel_to_users_table.php

xxxx_add_channel_to_users_table.php(一部抜粋)

    //(前略)

     public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('channel')->default('マイチャンネル');
        });
    }

    //(中略)

    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('channel');
        });
    }
}

$table->string('channel')で、「channel」というカラムを追加しており
default('マイチャンネル')という記述で、channelカラムの初期値を「マイチャンネル」に設定しています。

また、$table->dropColumn('channel');で、カラム削除のコマンドを示します。

記述ができたら、こちらのマイグレーションを実行して、カラム追加を行いましょう。

ターミナル

$ php artisan migrate

変更・追記箇所を書き加えていこう

カラムを追加したことで必要となる追記などの作業を行っていきます。

Router

Routerにて、チャンネル名・ユーザ名を変更する「rename」というルーティングをつくりましょう。
下記の内容で「Route::groupの中の記述」として、追記してください。
ログイン済みのユーザしか、名前変更のrenameルーティングにはアクセスできないようにするためです。

laravel-quest > routes > web.php

web.php(一部抜粋)

Route::group(['middleware' => 'auth'], function () {
    Route::put('users', 'UsersController@rename')->name('rename'); //追記
    Route::resource('movies', 'MoviesController', ['only' => ['create', 'store', 'destroy']]);
});

Controller

ルーティングの後は、コントローラにrenameアクションを追記していきましょう。

laravel-quest > app > Http > Controllers > UsersController.php

UsersController.php(追記分のみ)

    public function rename(Request $request)
    {
        $this->validate($request,[
                'channel' => 'required|max:15',
                'name' => 'required|max:15',
        ]);

        $user=\Auth::user();
        $movies = $user->movies()->orderBy('id', 'desc')->paginate(9);

        $user->channel = $request->channel;
        $user->name = $request->name;
        $user->save();
        
        $data=[
            'user' => $user,
            'movies' => $movies,
        ];
        
        $data += $this->counts($user);

        return view('users.show',$data);
    }

表示されたときの見た目も考えて、バリデーションによって文字数を最大15文字に限定しています。
今回は新規のユーザ登録ではないので、create()関数ではなく、save()関数によって保存処理を行っています。

View

表示名変更のためのView(変更フォーム)がなければ変更自体できませんので、show.blade.phpにフォームを作っていきましょう。

laravel-quest > resources > views > users > show.blade.php

show.blade.php

@extends('layouts.app')

@section('content')

<h1>{{ $user->name }}</h1>

<ul class="nav nav-tabs nav-justified mt-5 mb-2">
        <li class="nav-item nav-link {{ Request::is('users/' . $user->id) ? 'active' : '' }}"><a href="{{ route('users.show',['id'=>$user->id]) }}" class="">動 画<br><div class="badge badge-secondary">{{ $count_movies }}</div></a></li>
        <li class="nav-item nav-link"><a href="" class="">フォロワー<br><div class="badge badge-secondary"></div></a></li>
        <li class="nav-item nav-link"><a href="" class="">フォロー中<br><div class="badge badge-secondary"></div></a></li>
</ul>

@include('movies.movies', ['movies' => $movies])


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

        <h3 class="mt-5">表示名の変更</h3>

        <div class="row mt-5 mb-5">
            <div class="col-sm-6">

                    {!! Form::open(['route' => 'rename','method'=>'put']) !!}
                        <div class="form-group">
                            {!! Form::label('channel','チャンネル名') !!}
                            {!! Form::text('channel', $user->channel, ['class' => 'form-control']) !!}
                        </div>
        
                        <div class="form-group">
                            {!! Form::label('name','名前') !!}
                            {!! Form::text('name', $user->name, ['class' => 'form-control']) !!}
                        </div>
        
                        {!! Form::submit('更新する?', ['class' => 'button btn btn-primary mt-2']) !!}
                    {!! Form::close() !!}
                    
            </div>
        </div>
        
@endif

@endsection

今回は更新(Update)処理ですので、Form::openには 'method'=>'put' を記述しています。
また、Form::textの第2引数に $user->channel, $user->name とそれぞれ記述することによって、入力フォームの初期値に現在のチャンネル名やユーザ名が自動で入るようにしています。

また、ユーザ詳細ページにチャンネル名を表示させたいので、チャンネル名が表示されるように書き加え
名前の表示位置も少し変わるようにBootstrapのclassを変更しましょう。

show.blade.php(一部抜粋)

@extends('layouts.app')

@section('content')

<h1>{{ $user->channel }}</h1>
<h1 class="text-right">{{ $user->name }}</h1>

<ul class="nav nav-tabs nav-justified mt-5 mb-2">
 <!--後略-->

これでチャンネル名の表示〜表示名変更が実行できるかをプレビューで確認してみてください。

フォロー機能

次は、SNS機能の肝である「フォロー機能」を実装していきます。

多対多の関係

フォロー機能には、1対多の関係ではなく、多対多の関係を扱っていきます。
1対多の関係とどう違うのでしょうか。

1対多の関係では、ユーザが複数の動画を持っていて、動画は1人のユーザに所属しているという関係でした。
一方、今回の「フォローする」「フォローされる」という関係では、ユーザがフォローしているユーザ(followings)は複数いる可能性があります。逆に、あるユーザがフォローされているユーザも同様で、フォローされている相手(followers)は複数存在するかも知れません。

つまり、フォローしているユーザも、されているユーザもお互いに複数いる可能性があるのです。
これが1対多の関係との違いです。

中間テーブルとは?

https://puchohan.com/hobby/data-analysis/database-answer1
画像:上記サイト https://puchohan.com/hobby/data-analysis/database-answer1 より抜粋

1対多の関係では、user_idによってusersテーブルとmovies テーブルを繋ぎました。

多対多の関係では、1つのカラムでテーブルを繋ぐというやり方では不十分となりますので
「中間テーブル」と言われるものを、繋ぎたい「2者」の間に配置します。中間テーブルは、2者を結びつけるために存在します。

例えば、ID:2のユーザがID:5のユーザをフォローしている場合、
下記のような情報を「中間テーブル」に置きます。

| user_id:2 | follow_id:5 |

このように中間テーブルを記述して
ID:2のユーザがフォロー「している」、ID:5のユーザがフォロー「されている」という2者の関係を作っていきます。

注目して頂きたいのは、「ユーザ:中間テーブル」は、「1対多の関係」になっているということです。
下記のような関係性になります。

  • 「フォローしている」1人のユーザは、複数の中間テーブルのレコードに属している
  • 「フォローされている」1人のユーザは、複数の中間テーブルのレコードに属している

例えば、AさんがBさんをフォローしているとします。ですが、もしAさんがBさん以外のCさんもフォローしていたら、Aさんは1人で2つの中間テーブルのレコードに属しているということになります。

逆に、BさんがAさんにフォローされているとします。ですが、もしBさんがAさん以外のDさんにフォローされていたら、Bさんは1人で2つの中間テーブルのレコードに属しているということになります。

つまり、中間テーブルによって、ユーザが1人でも複数の関係性を保てることになります。
多対多の関係とは、1対多の関係を2つ結びつけたものということがいえるのです。

Model

マイグレーション

早速、フォロー機能を作成するための中間テーブルを作っていきましょう。
user_followテーブルを作るための、マイグレーションファイルを作成して下さい。

ターミナル

$ php artisan make:migration create_user_follow_table --create=user_follow

laravel-quest > database > migrations > xxxx_create_user_follow_table.php

xxxx_create_user_follow_table.php

<?php

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

class CreateUserFollowTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('user_follow', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('user_id')->unsigned()->index();
            $table->integer('follow_id')->unsigned()->index();
            $table->timestamps();
            
            // 外部キー制約
            $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
            $table->foreign('follow_id')->references('id')->on('users')->onDelete('cascade');

            // 組み合わせのダブりを禁止
            $table->unique(['user_id', 'follow_id']);
        });
    }

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

user_idとfollow_idというカラムを作ります。
「user_idをもつユーザ」が「follow_idをもつユーザ」をフォローしているという関係を作っていきます。
「follow_idって何かな」と思われた方もいると思いますが、user_idもfollow_idもともに「ユーザのID」を表しているに過ぎません。なので、厳密にいうと両者ともに「ユーザID」なのですが、同じ名前にするとややこしいので、カラム名をあえて変えているということです。

次に、moviesテーブル同様に、外部キー制約によって中間テーブルがusersテーブルとユーザIDによって結びついている関係性を示し
更に、その次の記述で二重フォローにならないように「ダブり」を禁止しています。

上記記述が出来たら、マイグレーションを実行しましょう。

ターミナル

$ php artisan migrate

Userモデルに多対多の関係を記述

中間テーブル専用のモデルを作っても良いのですが、専用のモデルを作らなくてもテーブルを操作できる便利なコマンドがあります。
中間テーブル用のモデルを作らない代わりに、それらのコマンドを用いつつ、Userモデルに多対多の関係を書いていくことにします。

laravel-quest > app > User.php

User.php

<?php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    //(中略)
    
    public function movies()
    {
        return $this->hasMany(Movie::class);
    }
    
    public function followings()
    {
        return $this->belongsToMany(User::class, 'user_follow', 'user_id', 'follow_id')->withTimestamps();
    }

    public function followers()
    {
        return $this->belongsToMany(User::class, 'user_follow', 'follow_id', 'user_id')->withTimestamps();
    }

    public function is_following($userId)
    {
        return $this->followings()->where('follow_id', $userId)->exists();
    }
    
    public function follow($userId)
    {
        // すでにフォロー済みではないか?
        $existing = $this->is_following($userId);
        // フォローする相手がユーザ自身ではないか?
        $myself = $this->id == $userId;
    
        // フォロー済みではない、かつフォロー相手がユーザ自身ではない場合、フォロー
        if (!$existing && !$myself) {
            $this->followings()->attach($userId);
        }
    }
    
    public function unfollow($userId)
    {
        // すでにフォロー済みではないか?
        $existing = $this->is_following($userId);
        // フォローする相手がユーザ自身ではないか?
        $myself = $this->id == $userId;
    
        // すでにフォロー済みならば、フォローを外す
        if ($existing && !$myself) {
            $this->followings()->detach($userId);
        }
    }
}

ここでモデルに多対多の関係を定義するために、followings()とfollowers()という関数を定義します。
関数の中身としては、下記の内容になります。

User.php(一部抜粋)

public function followings()
{
    return $this->belongsToMany(User::class, 'user_follow', 'user_id', 'follow_id')->withTimestamps();
}

public function followers()
{
    return $this->belongsToMany(User::class, 'user_follow', 'follow_id', 'user_id')->withTimestamps();
}

belongsToMany関数を用いて記述しており、これにより下記のようなシンプルなコードで「あるユーザのフォロー中のユーザ」「あるユーザのフォロワーとなっているユーザ」を取得できることになります。

  • あるユーザのフォロー中のユーザを取得する: $user->followings
  • あるユーザのフォロワーとなっているユーザ を取得する: $user->followers

また、followings()関数の中身の引数の意味は以下の通りです。

  • 第1引数:「Userモデルが、別の複数のUserモデルに所属している」ということを明示
  • 第2引数:user_followテーブルという「中間テーブル」でユーザ同士が繋がっていることを示す
  • 第3引数:中間テーブルに保存されている主体となるユーザ自身のIDカラム(user_id)を設定
  • 第4引数:中間テーブルに保存されている関係先(相手)ユーザのIDカラム(follow_id)を設定

followings()で「あるユーザがフォローしているユーザ」を取得できます。
followers()は、 第3引数と第4引数を逆にして、「 あるユーザ をフォローしているユーザ」を取得できるようにしています。

多対多の関係 Laravel ドキュメント
https://readouble.com/laravel/5.5/ja/eloquent-relationships.html#many-to-many

follow(), unfollow()

また、ボタンを押すと「フォロー」を実行できたり、「フォローを外す」が実行できるようにするための関数として、follow() 関数とunfollow()関数を記述しています。

User.php(一部抜粋)

    public function is_following($userId)
    {
        return $this->followings()->where('follow_id', $userId)->exists();
    }

    public function follow($userId)
    {
        // すでにフォロー済みではないか?
        $existing = $this->is_following($userId);
        // フォローする相手がユーザ自身ではないか?
        $myself = $this->id == $userId;
    
        // フォロー済みではない、かつフォロー相手がユーザ自身ではない場合、フォロー
        if (!$existing && !$myself) {
            $this->followings()->attach($userId);
        }
    }
    
    public function unfollow($userId)
    {
        // すでにフォロー済みではないか?
        $existing = $this->is_following($userId);
        // フォローを外す相手がユーザ自身ではないか?
        $myself = $this->id == $userId;
    
        // すでにフォロー済み、かつフォロー相手がユーザ自身ではない場合、フォローを外す
        if ($existing && !$myself) {
            $this->followings()->detach($userId);
        }
    }

これにより、下記コードで「フォローする」「フォローを外す」機能が実行できます。

  • フォローする:  $user->follow($userId)
  • フォローを外す:  $user->unfollow($userId)

follow() 関数とunfollow()関数を実装するときには、
「すでにフォロー済みではないか?」「フォローする相手がユーザ自身ではないか?」の2点を確認する必要があります。

最初に記述されているis_following()関数により、フォロー対象のユーザIDが、すでにフォローしているfollow_idと重複していないかどうかを判定し
次に、フォロー対象のユーザIDがユーザ自分自身のIDと一致しているかどうかを判定します。

この2つを判定してから、「フォロー」 「フォローを外す」 機能が実行されるようにしましょう。

「フォロー」 を実行することは、中間テーブルに情報を保存することを意味し、
「フォローを外す」を実行することは、中間テーブルから情報を削除することを意味します。
便利なコマンドであるattach()関数とdetach()関数を用いることで、中間テーブルのレコードを簡単に作成・消去することが可能です。

attachとdetach Laravelドキュメント
https://readouble.com/laravel/5.5/ja/eloquent-relationships.html#updating-many-to-many-relationships

tinkerでフォロー機能を試そう

試しに、tinkerで「フォロー」「フォローを外す」を実行してみましょう。
フォローするには、2名以上のユーザを作成しておく必要がありますので、2名以上のユーザが登録されていない方は、新規ユーザ登録フォームからでもtinker上でも構いませんので、下記コマンドを実行する前にユーザ登録をしておきましょう。

ターミナル

>>> use App\User
>>> $user1 = User::find(1)
=> App\User {#xxx
     id: 1,
     name: "aaa",
     email: "aaaaaa@aaaaaa.com",
     created_at: "2019-12-01 12:58:46",
     updated_at: "2019-12-07 21:01:12",
     channel: "aaaチャンネル",
   }
>>> $user2 = User::find(2)
=> App\User {#xxx
     id: 2,
     name: "bbb",
     email: "bbbbbb@bbbbbb.com",
     created_at: "2019-12-01 12:58:46",
     updated_at: "2019-12-07 21:01:12",
     channel: "bbbチャンネル",
}
>>> $user1->follow($user2->id)
=> null
>>> $user1->followings()->get()
=> Illuminate\Database\Eloquent\Collection {#xxx
     all: [
       App\User {#xxx
         id: 2,
         name: "bbb",
         email: "bbbbbb@bbbbbb.com",
         created_at: "2019-12-07 13:37:10",
         updated_at: "2019-12-07 13:37:10",
         channel: "bbbチャンネル",
         pivot: Illuminate\Database\Eloquent\Relations\Pivot {#xxx
           user_id: 1,
           follow_id: 2,
           created_at: "2019-12-07 21:33:05",
           updated_at: "2019-12-07 21:33:05",
         },
       },
     ],
   }
>>> $user2->followers()->get() 
     all: [
       App\User {#2927
         id: 1,
         name: "aaa",
         email: "aaaaaa@aaaaaa.com",
         created_at: "2019-12-01 12:58:46",
         updated_at: "2019-12-07 21:01:12",
         channel: "aaaチャンネル",
         pivot: Illuminate\Database\Eloquent\Relations\Pivot {#2923
           follow_id: 2,
           user_id: 1,
           created_at: "2019-12-07 21:35:00",
           updated_at: "2019-12-07 21:35:00",
         },
       },
     ],
   }
>>> $user1->unfollow($user2->id)
=> null
>>> $user1->followings()->get()
=> Illuminate\Database\Eloquent\Collection {#xxx
     all: [],
   }

上記が実行できましたら、フォロー機能が正常に実行できるということです。

Router

続いて、「フォロー」「フォローを外す」ためのルーティングやアクションを作っていきましょう。

laravel-quest > routes > web.php

web.php(一部抜粋)

Route::resource('users', 'UsersController', ['only' => ['show']]);

Route::group(['prefix' => 'users/{id}'], function () {
    Route::get('followings', 'UsersController@followings')->name('followings');
    Route::get('followers', 'UsersController@followers')->name('followers');
    });

Route::group(['middleware' => 'auth'], function () {
    Route::put('users', 'UsersController@rename')->name('rename');
    
    Route::group(['prefix' => 'users/{id}'], function () {
        Route::post('follow', 'UserFollowController@store')->name('follow');
        Route::delete('unfollow', 'UserFollowController@destroy')->name('unfollow');
    });
    
    Route::resource('movies', 'MoviesController', ['only' => ['create', 'store', 'destroy']]);
});

フォローにまつわる4つのルーティングを追記しています。

ログイン認証を通っていないユーザでも、「誰が誰をフォローしているのか」を確認できるようにしたいと思いますので
フォロー中のユーザを取得するfollowingsルーティングと、フォロワーを取得するfollowersルーティングに関してはログイン認証を通っていないユーザでもアクセスできるようにします。

逆に、ログイン認証(auth)を通過したユーザだけがアクセスできるルーティング内に、followルーティングとunfollowルーティングを設けて、ログインユーザのみが「フォロー」「フォローを外す」を実行できるようにしています。

ちなみに、フォロー関連の4つのルーティングは、['prefix' => 'users/{id}']と記述したルーティンググループを設けて
「どのユーザのフォロワー・フォロー中のユーザを操作・表示するのか」を明示するようにしています。

これは何を示しているかというと、URLに「/users/{ユーザのID番号}/」が記載されるということです。
つまり、followルーティングの場合(ユーザID1番の場合)、URLは下記のような形になります。

URL例)https://●●●●/users/1/follow

UserFollowController storeアクション, destroyアクション

Controller

Model/Routerの記述ができましたので、Controllerを記述していきます。

UsersController.phpやMoviesController.phpが存在するのですが、今回は「中間テーブル」に関わるアクションとして、他のコントローラと分けてつくりましょう。
ファイル名は UserFollowController.php として、下記の様に書きましょう。

ターミナル

$ php artisan make:controller UserFollowController

app/Http/Controllers/UserFollowController.php の store と destroy

laravel-quest > app > Http > Controllers > UserFollowController.php

UserFollowController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class UserFollowController extends Controller
{
    public function store($id)
    {
        \Auth::user()->follow($id);
        return back();
    }

    public function destroy($id)
    {
        \Auth::user()->unfollow($id);
        return back();
    }
}

store関数は、ユーザが他のユーザをフォローする処理を担当します。
反対に、destroy関数は、ユーザがしているフォローを外す処理を担います。

Userモデルに記述したfollow関数とunfollow関数を利用して記述しています。

フォロー中の数、フォロワーの数

ユーザが所有している動画の数を、counts関数を使って表示させる処理をしていましたが
ここでは、ユーザがフォロー中の数、ユーザのフォロワーの数をそれぞれ表示させたいと思います。

動画の所有数のときと同じく、 Controllerクラスの中の counts関数 に記述することで
すべてのコントローラで フォロー中の数 ・ フォロワーの数を取得できるようにしましょう。

app/Http/Controllers/Controller.php

laravel-quest > app > Http > Controllers > Controller.php

Controller.php

<?php

namespace App\Http\Controllers;

use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;

class Controller extends BaseController
{
    use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
    
    
    public function counts($user) {
        $count_movies = $user->movies()->count();
        $count_followings = $user->followings()->count();
        $count_followers = $user->followers()->count();

        return [
            'count_movies' => $count_movies,
            'count_followings' => $count_followings,
            'count_followers' => $count_followers,
        ];
    }
}

動画数を取得する記述と全く同じ要領で、上記の様に記述して下さい。

View

「フォローする」ボタンをつくろう

「フォローする」ボタン、「フォローを外す」ボタンは複数の場所に出現させたいので
ボタン専用のViewファイルをつくって、共通化させましょう。

laravel-quest > resources > views > follow > follow_button.blade.php

follow_button.blade.php

@if(Auth::check())

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

        @if (Auth::user()->is_following($user->id))
        
            {!! Form::open(['route' => ['unfollow', $user->id], 'method' => 'delete']) !!}
                {!! Form::submit('このユーザのフォローを外す', ['class' => "button btn btn-danger mt-1"]) !!}
            {!! Form::close() !!}
            
        @else
        
            {!! Form::open(['route' => ['follow', $user->id]]) !!}
                {!! Form::submit('このユーザをフォローする', ['class' => "button btn btn-primary mt-1"]) !!}
            {!! Form::close() !!}
            
        @endif
    
    @endif

@endif

@if(Auth::check())により、ユーザがログイン認証を通っている場合のみ、ボタンを表示させるようにしています。

かつ、@if (Auth::id() != $user->id)の記述により、ユーザが自分自身をフォローできないように、自分のIDと一致しないユーザIDに対してのみ、ボタンを表示させています。

上記ファイルを、ボタンを表示させたい場所で@includeすると、 「フォローする」ボタン もしくは 「フォローを外す」ボタンが表示されます。

ボタンの配置

「フォローする」ボタン「フォローを外す」ボタンを、トップページのユーザ一覧(users.blade.php)に置いていきましょう。
コメントの下にボタンを表示させるようにしましょう。

laravel-quest > resources > views > users > users.blade.php

users.blade.php(一部抜粋)

<!--前略-->

                    <p>
                        @if(isset($movie->comment))
                               {{ $movie->comment }}
                        @endif
                    </p>
                    
                        @include('follow.follow_button',['user'=>$user])

                </div>
                
            </div>

    @endforeach

</div>

{{ $users->links('pagination::bootstrap-4') }}

ここまでで、トップページのプレビュー上にフォローボタンが表示されるか確認してみましょう。

UsersController followingsアクション, followersアクション

Controller

ユーザ個別詳細ページ(マイページ)に、フォロー中・フォロワーの一覧を表示させるようにしていきます。

まずはUsersController にフォロー中・フォロワーのユーザ情報を抽出する記述をしましょう。

laravel-quest > app > Http > Controllers > UsersController.php

UsersController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\User;

class UsersController extends Controller
{

    //(中略)
    
    public function followings($id)
    {
        $user = User::find($id);
        $followings = $user->followings()->paginate(9);

        $data = [
            'user' => $user,
            'users' => $followings,
        ];

        $data += $this->counts($user);

        return view('users.followings', $data);
    }

    public function followers($id)
    {
        $user = User::find($id);
        $followers = $user->followers()->paginate(9);

        $data = [
            'user' => $user,
            'users' => $followers,
        ];

        $data += $this->counts($user);

        return view('users.followers', $data);
    }
}

View

下記ページは、タブによって表示を切替えできるようにするのですが、共通している部分があります。

  • ユーザの動画一覧ページ(show.blade.php)
  • ユーザのフォロー中一覧ページ(followings.blade.php)
  • ユーザのフォロワー一覧ページ(followers.blade.php)

なので、共通している部分の内容を、タブ(tabs.blade.php)として切り分けましょう。
タブの中には、 followingsページ と followersページ に行けるリンクも入れておきましょう。
また、ユーザ詳細ページからも、そのユーザをフォローできるように、ユーザ名の下に「フォローボタン」も設置しておきましょう。

laravel-quest > resources > views > users > tabs.blade.php

tabs.blade.php

<h1>{{ $user->channel }}</h1>
<h1 class="text-right">{{ $user->name }}</h1>

@include('follow.follow_button', ['user' => $user])

<ul class="nav nav-tabs nav-justified mt-5 mb-2">
        <li class="nav-item nav-link {{ Request::is('users/' . $user->id) ? 'active' : '' }}"><a href="{{ route('users.show',['id'=>$user->id]) }}" class="">動 画<br><div class="badge badge-secondary">{{ $count_movies }}</div></a></li>
        <li class="nav-item nav-link {{ Request::is('users/*/followers') ? 'active' : '' }}"><a href="{{ route('followers',['id'=>$user->id]) }}" class="">フォロワー<br><div class="badge badge-secondary">{{ $count_followers }}</div></a></li>
        <li class="nav-item nav-link {{ Request::is('users/*/followings') ? 'active' : '' }}"><a href="{{ route('followings',['id'=>$user->id]) }}" class="">フォロー中<br><div class="badge badge-secondary">{{ $count_followings }}</div></a></li>
</ul>

laravel-quest > resources > views > users > show.blade.php

show.blade.php

@extends('layouts.app')

@section('content')

        @include('users.tabs',['user'=>$user])

        @include('movies.movies', ['movies' => $movies])

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

        <h3 class="mt-5">表示名の変更</h3>

        <div class="row mt-5 mb-5">
            <div class="col-sm-6">

                    {!! Form::open(['route' => 'rename','method'=>'put']) !!}
                        <div class="form-group">
                            {!! Form::label('channel', 'チャンネル名') !!}
                            {!! Form::text('channel', $user->channel, ['class' => 'form-control']) !!}
                        </div>
        
                        <div class="form-group">
                            {!! Form::label('name', '名前') !!}
                            {!! Form::text('name', $user->name, ['class' => 'form-control']) !!}
                        </div>
        
                        {!! Form::submit('更新する?', ['class' => 'button btn btn-primary mt-2']) !!}
                    {!! Form::close() !!}
            
            </div>
        </div>

@endif

@endsection

次に、フォロー中・フォロワーの一覧ページのViewを作っていきます。

laravel-quest > resources > views > users > followings.blade.php

followings.blade.php

@extends('layouts.app')

@section('content')

            @include('users.tabs',['user'=>$user])

            @include('users.users',['users'=>$users])

@endsection

laravel-quest > resources > views > users > followers.blade.php

followers.blade.php

@extends('layouts.app')

@section('content')

            @include('users.tabs',['user'=>$user])

            @include('users.users',['users'=>$users])

@endsection

フォロー中一覧ページ・フォロワーの一覧ページは、同じ内容となっていますが
今後それぞれのページで違いを出す部分も出てくるかも知れませんので、念のためファイルを別で用意しています。

あとは、この内容をプレビューで問題なく表示できれば完成です。
フォローしたユーザやフォローされているユーザが、フォロー中一覧ページ・フォロワーの一覧ページに表示されましたでしょうか?

今回の講義は以上となります。
お疲れ様でした!

次回はこちら

https://yu-nocode.com/entry/laravel-quest-6

この記事が気に入ったら
フォローしよう

最新情報をお届けします

Twitterでフォローしよう

おすすめの記事