【全6回】Laravel5.8でTwitterっぽいSNSツールを作る（第2回Seeder->ログイン/新規登録）

# Laravelで始めるTwitter風（Twitterクローン）のSNSツール開発チュートリアル

## 概要

スクールとかの課題だったりLaravelを初めてみたいけど何を作ろうって迷ってる人向けによくあるTwitter風のWEBサイトを作ってみます。

### 前回

- 第1回 [【全6回】Laravel5.8でTwitterっぽいSNSツールを作る（第1回DB設計とMigration）](https://qiita.com/namizatop/items/d79017aa474966244073)
- 第2回 [【全6回】Laravel5.8でTwitterっぽいSNSツールを作る（第2回Seeder->ログイン/新規登録）](https://qiita.com/namizatop/items/3c20c0d0565906cc6a1a)
- 第3回 [【全6回】Laravel5.8でTwitterっぽいSNSツールを作る（第3回ユーザ関連とフォロー機能）](https://qiita.com/namizatop/items/0c81b0a94a1084cda6de)
- 第4回 [【全6回】Laravel5.8でTwitterっぽいSNSツールを作る（第4回ツイートのCRUD機能）](https://qiita.com/namizatop/items/c9ed67f98fc3e5ce67c7)
- 第5回 [【全6回】Laravel5.8でTwitterっぽいSNSツールを作る（第5回ツイートのCRUD機能 編集と削除）](https://qiita.com/namizatop/items/2273bd0dcc817785b131)
- 第6回 [【全6回】Laravel5.8でTwitterっぽいSNSツールを作る（第6回コメントといいね機能）](https://qiita.com/namizatop/items/0f3f8783c93f3dfa277d)

第2回はシーディングを実行した後にログイン/新規登録までやっていきます。

## 前提

- PHPをある程度理解している
- Laravelが使える環境がある
- MVC構造をある程度理解している

## 環境

- Mac
- Homestead
- Laravel 5.8

## Seeder

前回Migrationを使ってテーブルの構築とModelのリレーションを設定しました。
今回は作ったテーブルにSeederという予めLaravelに用意された機能を利用してテストデータを投入しましょう。

ターミナルで以下のコマンドを叩くと`database/seeds/`の中に`SamplesTableSeeder`というファイルが生成されます。

```terminal
php artisan make:seeder SamplesTableSeeder
```

この要領で前回作成したテーブルをまとめて作成しましょう。

```terminal
php artisan make:seeder UsersTableSeeder
php artisan make:seeder TweetsTableSeeder
php artisan make:seeder CommentsTableSeeder
php artisan make:seeder FavoritesTableSeeder
php artisan make:seeder FollowersTableSeeder
```

では実際にテストデータを投入していきます。

### UsersTableSeeder

ユーザを10人ほど登録しておきたいのでforで登録を10回繰り返します。
パスワードを変更したければ`Hash::make('12345678')`の中身を変更してください。

```php:database/seeds/UsersTableSeeder.php
<?php

use Illuminate\Database\Seeder;
use App\Models\User;

class UsersTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        for ($i = 1; $i <= 10; $i++) {
            User::create([
                'screen_name'    => 'test_user' .$i,
                'name'           => 'TEST' .$i,
                'profile_image'  => 'https://placehold.jp/50x50.png',
                'email'          => 'test' .$i .'@test.com',
                'password'       => Hash::make('12345678'),
                'remember_token' => str_random(10),
                'created_at'     => now(),
                'updated_at'     => now()
            ]);
        }
    }
}
```

### TweetsTableSeeder

ツイート投稿も各ユーザー毎に1件登録しておきます。

```php:database/seeds/TweetsTableSeeder.php
<?php

use Illuminate\Database\Seeder;
use App\Models\Tweet;

class TweetsTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        for ($i = 1; $i <= 10; $i++) {
            Tweet::create([
                'user_id'    => $i,
                'text'       => 'これはテスト投稿' .$i,
                'created_at' => now(),
                'updated_at' => now()
            ]);
        }
    }
}
```

### CommentsTableSeeder

ユーザID1のユーザが各ユーザに1つコメントしておきます。

```php:database/seeds/CommentsTableSeeder.php
<?php

use Illuminate\Database\Seeder;
use App\Models\Comment;

class CommentsTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        for ($i = 1; $i <= 10; $i++) {
            Comment::create([
                'user_id' => 1,
                'tweet_id' => $i,
                'text' => 'これはテストコメント' .$i,
                'created_at' => now(),
                'updated_at' => now()
            ]);
        }
    }
}
```

### FavoritesTableSeeder

ユーザID1が自分を除くツイートに対して1ついいねを付ける

```php:database/seeds/FavoritesTableSeeder.php
<?php

use Illuminate\Database\Seeder;
use App\Models\Favorite;

class FavoritesTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        for ($i = 2; $i <= 10; $i++) {
            Favorite::create([
                'user_id' => 1,
                'tweet_id' => $i
            ]);
        }
    }
}
```

### FollowersTableSeeder

ユーザID1を各ユーザがフォローして置く

```php:database/seeds/FollowersTableSeeder.php
<?php

use Illuminate\Database\Seeder;
use App\Models\Follower;

class FollowersTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        for ($i = 2; $i <= 10; $i++) {
            Follower::create([
                'following_id' => $i,
                'followed_id' => 1
            ]);
        }
    }
}
```

### DatabaseSeeder

ではコマンドを叩いた時に全てのSeederデータが投入されるように`DatabaseSeeder.php`というファイルに
実行するファイル名を記述しておきます。

**※`$this->call()`の中で上から順に実行されるため以下の並びでないとテーブルの親子関係上エラーになります**

```php:database/seeds/DatabaseSeeder.php
<?php

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        $this->call([
            UsersTableSeeder::class,
            TweetsTableSeeder::class,
            CommentsTableSeeder::class,
            FavoritesTableSeeder::class,
            FollowersTableSeeder::class,
        ]);
    }
}
```

ここまで出来たら準備は完了です。

## Seeder実行

Seederの実行はターミナルで以下のコマンドを叩くだけで実行できます。

```terminal
php artisan db:seed
```
これでテストデータの登録は完了です。

## ログイン/新規登録

素のPHPをやってた人はログインと新規登録の実装がどれだけ大変か分かると思います。
しかし、Laravelでは以下のコマンドを叩くだけでAuth認証の全てを実装してくれます。

```terminal
php artisan make:auth
```

Auth認証が実装されると`routes/web.php`に以下のコードが記述されます。

```php:routes/web.php
Auth::routes();

Route::get('/home', 'HomeController@index')->name('home');
```

細かな説明は省きますが`app/Http/Controllers/Auth/`のファイルを自動で読み込むようになるので
ログイン機能が使えるようになります。

> 右上に`LOGION`と`REGISTER`が追加されている

<img width="1440" alt="スクリーンショット 2019-08-17 17.54.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293438/68b96acc-e48b-19a4-e8ec-a1f31fe441af.png">

> Auth認証の参考
[Laravelのユーザー認証機能（Auth）の実装フロー](https://www.terakoya.work/laravel-make-auth-exec-flow/)

### ログイン

では右上の`LOGIN`というボタンを押して先ほどSeederで登録したユーザ情報を使ってログインしてみましょう。

<img width="1440" alt="スクリーンショット 2019-08-17 17.58.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293438/55466e08-c714-68e4-1aa5-c23a8e597ffb.png">

エラーが出ました。
これは`app/User.php`をapp/Models/User.php`に移動したために起きたエラーのようです。

以下のファイルの`App\User`となっている部分を全て`App\Models\User`という風に変更してください。

- RegisterController.php
- auth.php

そして自動でファイルを呼び出すautoloadもターミナルにて更新しておきます。

```terminal
composer dump-autoload
```

これでログインすると無事にログインできるとと思います。

<img width="1440" alt="スクリーンショット 2019-08-17 18.05.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293438/106151a0-db6b-ef06-b784-b317bb1bffd2.png">

では一旦右上のLogoutボタンを押して先ほどの画面に戻り、新規登録してみましょう。

こちらもエラーが出たと思います。

<img width="1440" alt="スクリーンショット 2019-08-17 18.09.40.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293438/2a42b776-19c0-1340-2c18-404d6ad66a33.png">

こちらはusersテーブルに`screen_name`カラムを追加してnullを許可しない設定にしたけど
新規登録時にその該当カラムが見つからないよ！というエラーみたいです。
※`profile_image`はnullを許可しているので一旦無視します。

`app/Http/Conrollers/Auth/RegisterConroller.php`を開いて以下のように編集します。

```php:app/Http/Conrollers/Auth/RegisterConroller.php
<?php

namespace App\Http\Controllers\Auth;

use App\Models\User;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Foundation\Auth\RegistersUsers;

class RegisterController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Register Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles the registration of new users as well as their
    | validation and creation. By default this controller uses a trait to
    | provide this functionality without requiring any additional code.
    |
    */

    use RegistersUsers;

    /**
     * Where to redirect users after registration.
     *
     * @var string
     */
    protected $redirectTo = '/home';

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest');
    }

    /**
     * Get a validator for an incoming registration request.
     *
     * @param  array  $data
     * @return \Illuminate\Contracts\Validation\Validator
     */
    protected function validator(array $data)
    {
        return Validator::make($data, [
            // 追加
            'screen_name' => ['required', 'string', 'max:255', 'unique:users'],
            'name'        => ['required', 'string', 'max:255'],
            'email'       => ['required', 'string', 'email', 'max:255', 'unique:users'],
            'password'    => ['required', 'string', 'min:8', 'confirmed'],
        ]);
    }

    /**
     * Create a new user instance after a valid registration.
     *
     * @param  array  $data
     * @return \App\Models\User
     */
    protected function create(array $data)
    {
        return User::create([
            // 追加
            'screen_name' => $data['screen_name'],
            'name' => $data['name'],
            'email' => $data['email'],
            'password' => Hash::make($data['password']),
        ]);
    }
}
```

その後に`resources/views/auth/register.blade.php`も同様に修正します。

```php:resources/views/auth/register.blade.php
@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">{{ __('Register') }}</div>

                <div class="card-body">
                    <form method="POST" action="{{ route('register') }}">
                        @csrf

                        <!-- 追加 -->
                        <div class="form-group row">
                            <label for="screen_name" class="col-md-4 col-form-label text-md-right">{{ __('Account Name') }}</label>

                            <div class="col-md-6">
                                <input id="screen_name" type="text" class="form-control @error('screen_name') is-invalid @enderror" name="screen_name" value="{{ old('screen_name') }}" required autocomplete="screen_name" autofocus>

                                @error('screen_name')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>
                        </div>

                        <div class="form-group row">
                            <label for="name" class="col-md-4 col-form-label text-md-right">{{ __('Name') }}</label>

                            <div class="col-md-6">
                                <input id="name" type="text" class="form-control @error('name') is-invalid @enderror" name="name" value="{{ old('name') }}" required autocomplete="name" autofocus>

                                @error('name')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>
                        </div>

                        <div class="form-group row">
                            <label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>

                            <div class="col-md-6">
                                <input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email">

                                @error('email')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>
                        </div>

                        <div class="form-group row">
                            <label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>

                            <div class="col-md-6">
                                <input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="new-password">

                                @error('password')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>
                        </div>

                        <div class="form-group row">
                            <label for="password-confirm" class="col-md-4 col-form-label text-md-right">{{ __('Confirm Password') }}</label>

                            <div class="col-md-6">
                                <input id="password-confirm" type="password" class="form-control" name="password_confirmation" required autocomplete="new-password">
                            </div>
                        </div>

                        <div class="form-group row mb-0">
                            <div class="col-md-6 offset-md-4">
                                <button type="submit" class="btn btn-primary">
                                    {{ __('Register') }}
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection
```

これで新規登録も行けたと思います。
一旦今回はここまで( ◠‿◠ )

次回 -> [【全6回】Laravel5.8でTwitterっぽいSNSツールを作る（第3回ユーザ関連とフォロー機能）](https://qiita.com/namizatop/items/0c81b0a94a1084cda6de)