【初心者向け】LaravelでYoutubeのお気に入りCuration(まとめ)アプリを作る【第3回: 新規ユーザ登録実装】

こんにちは。
ITエンジニアの濱辺(ハマベ)です。

前回に引き続き、お気に入りの動画を共有できる、SNSのようなアプリを作っていきます。

前回は、DB周りをやりました。

第３回は、主に、新規登録機能周りを作成していきます。

↓第2回はこちら
[LaravelでYoutubeのお気に入りCuration(まとめ)アプリを作る【第2回】](https://qiita.com/dogabon20/items/bd376085f4fdecdaeb99)

↓こちらの画面定義書のものを作っていきます。
[Youtube-Curation 画面定義所 (googleスプレッドシート)](https://docs.google.com/spreadsheets/d/1BglTVpnsappqNFoNTnmr1NfkRqT47VFF_u4Z4MvAu3w/edit#gid=68179162)

## トップページを作る

まずは**router**を作成します。

routerの作成とは、このURLにアクセスしたら、このページを表示してね、という決まり事を決めることです。

`router/web.php`に下記を記述します。

```web.php
Route::get('/', function () {
    return view('welcome');
});
```

これは、ホームディレクトリにアクセスされたら、welcomeというページを表示してね。
という指令になります。

## 共通部分を切り分けて作成する

当ページ最初の方のリンクから見ることができる、画面定義書を確認すると分かるかと思いますが、全てのページで共通して存在する部分があります。

そこをいちいち全てのページに記述していくのは効率が悪く、修正があった際の手間も増えます。

なので、共通部分は、部品として使いまわせるように切り分けて作成します。

`resources/views/layouts/app.blade.php`を新規作成しましょう。

```app.blade.php
<!DOCTYPE html>
<html lang="ja">

    <head>

        <meta charset="utf-8">
        <title>YouTubeまとめ×SNS</title>
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">

    </head>

    <body>

        @include('commons.header')

        <div class="container">

            @include('commons.error_messages')

            @yield('content')

        </div>

        @include('commons.footer')

        <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
        <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
        <script defer src="https://use.fontawesome.com/releases/v5.7.2/js/all.js"></script>

    </body>

</html>
```

このコードは**全てのページに反映されます。**

@includeは、他のviewを呼び出してあてはめる指示をするコードです。
例えば`@include('commons.header')`の部分は、今後`commons/header.blade.php`を作成してコードを記述すれば、そのコードがそのまま当てはまって見た目として表示されるわけです。

こうして部品かすることで、管理しやすく、修正に強い設計ができます。フレームワークの長所の一つです。

## view:エラーメッセージ作成

エラーメッセージを表示させるファイルを作っていきます。

`views/commons/error_messages.blade.php`を新規作成しましょう。

```error_messages.blade.php
@if (count($errors) > 0)
    <ul class="alert alert-danger">
        @foreach ($errors->all() as $error)
            <li class="ml-4">{{ $error }}</li>
        @endforeach
    </ul>
@endif
```

ざっくり言うと、**もしもエラーがあるなら、$errorを表示しろ**という指示を出しています。

これが先程の`app.blade.php`内の`@include('commons.error_messages')`にあてがわれるわけです。

## ヘッダーとフッターを作成

先程作ったcommonsフォルダの中に、`header.blade.php`,`footer.blade.php`を作成しましょう。

```header.blade.php
<header class="mb-5">

    <nav class="navbar navbar-expand-lg navbar-light bg-light">

        <a class="navbar-brand" href="/">YouTube-Curation</a>

        <button type="button" class="navbar-toggler" data-toggle="collapse" data-target="#nav-bar">
            <span class="navbar-toggler-icon"></span>
        </button>

        <div class="collapse navbar-collapse" id="nav-bar">
            <ul class="navbar-nav mr-auto"></ul>
            <ul class="navbar-nav">
                <li class="nav-item"><a href="" class="nav-link">新規ユーザ登録</a></li>
                <li class="nav-item"><a href="" class="nav-link">ログイン</a></li>
            </ul>
        </div>

    </nav>

</header>
```

```footer.blade.php
<footer class="mt-5">
        <nav class="navbar navbar-light bg-light justify-content-center">
                <div class="navbar-brand m-0">© QuestAcademia, All rights reserved.</div>
        </nav>
</footer>
```

## welcome.blade.phpを改変

welcome.blade.phpは最初からコードが記述されていますが、全て削除して書き換えます。

```welcome.blade.php
@extends('layouts.app')

@section('content')

    <div class="center jumbotron bg-warning">

        <div class="text-center text-white">
            <h1>YouTubeまとめ × SNS</h1>
        </div>

    </div>

@endsection
```

この状態で、[http://127.0.0.1:8080/](http://127.0.0.1:8080/)にアクセスすると、下記画像と同じものが表示されます。

![スクリーンショット 2021-10-02 20.12.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1209814/024f4f0a-e599-20cb-40d9-5906ae8519a7.png)

## 新規登録機能を実装

さて、トップページの最低限の見た目が出来たので、いよいよ機能実装をしていきます。
MVCのC、Controllerを使用するのですが、新規登録のためのコントローラは、Laravelに標準で備わっています。

`app/Http/Controllers/Auth/RegisterController.php`が該当のファイルです。
とりあえず、このファイルは一旦置いて、先にrouterを作っていきましょう。

`web.php`を開き、最下部に下記を追加しましょう。

```web.php
// ユーザ登録
Route::get('signup', 'Auth\RegisterController@showRegistrationForm')->name('signup');
Route::post('signup', 'Auth\RegisterController@register')->name('signup.post');
```

->name() という記述により、ルーティングに命名して後で呼び出しやすくしています。

#### コントローラの実装

`RegisterController.php`を開きましょう。

```RegisterController.php(一部抜粋)
<?php

namespace App\Http\Controllers\Auth;

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

~ 略

    protected function create(array $data)
    {
        return User::create([
            'name' => $data['name'],
            'email' => $data['email'],
            'password' => Hash::make($data['password']),
        ]);
    }
}
```

上記ファイルのうち、`protected $redirectTo = RouteServiceProvider::HOME;`行のみ、下記に変更しましょう。

```
protected $redirectTo = '/';
```

さて、controllerにはほぼ何もしていないですが、すでに正常に新規登録機能が動作するようになっています。

それは、「トレイト」と呼ばれる機能のおかげです。
先ほど`web.php`に記述した、下記をみてください。

```web.php
Route::get('signup', 'Auth\RegisterController@showRegistrationForm')->name('signup');
Route::post('signup', 'Auth\RegisterController@register')->name('signup.post');
```

`Auth/RegisterController`の、`showRegistrationForm`,`register`アクションを呼ぶ記述になっていますが、そんなアクションはどこにも記述されていません。ではなぜ、正常に動作するのか、それは、「トレイト」ざっくりいうと、どこかの誰かが作ったアクションを使用している、からです。

今回使用しているアクションの元コードは以下で確認できます。
https://github.com/laravel/framework/blob/6.x/src/Illuminate/Foundation/Auth/RegistersUsers.php

その他、**処理を行うにはゲストユーザでなくてはならない**, **新規登録したらトップページに戻る**, **255文字以上入力できない(バリデーション)**などの処理が書かれているのですが、細かい説明は省きます。

## LaravelCollective 導入

新規登録の処理は実装したので、登録画面のviewを作成します。
view作成に`LaravelCollective`というライブラリを使用するので、先にインストールしましょう。

```
# composer require "laravelcollective/html":"6.*"
```

↓ここで一旦、`RegistersUsers`を見てみましょう。
https://github.com/laravel/framework/blob/6.x/src/Illuminate/Foundation/Auth/RegistersUsers.php

この中の`showRegistrationForm`のコードを見てみましょう。

```
return view('auth.register');
```

これは、`Auth/register.blade.php`ファイルを表示する、という処理です。
しかし、そんなファイルは存在しないため、新規作成しましょう。

`resources/views/auth/register.blade.php`を作成。

```register.blade.php
@extends('layouts.app')

@section('content')

    <div class="center jumbotron bg-warning">
        <div class="text-center text-white">
            <h1>YouTubeまとめ × SNS</h1>
        </div>
    </div>

    <div class="text-center">
        <h3 class="login_title text-left d-inline-block mt-5">新規ユーザー登録</h3>
    </div>

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

            {!! Form::open(['route' => 'signup.post']) !!}
                <div class="form-group">
                    {!! Form::label('name', '名前') !!}
                    {!! Form::text('name', old('name'), ['class' => 'form-control']) !!}
                </div>

                <div class="form-group">
                    {!! Form::label('email', 'メールアドレス') !!}
                    {!! Form::email('email', old('email'), ['class' => 'form-control']) !!}
                </div>

                <div class="form-group">
                    {!! Form::label('password', 'パスワード') !!}
                    {!! Form::password('password', ['class' => 'form-control']) !!}
                </div>

                <div class="form-group">
                    {!! Form::label('password_confirmation', 'パスワード確認') !!}
                    {!! Form::password('password_confirmation', ['class' => 'form-control']) !!}
                </div>

                {!! Form::submit('新規登録', ['class' => 'btn btn-primary mt-2']) !!}
            {!! Form::close() !!}

        </div>
    </div>

@endsection
```

**{!! !!}** は、LaravelCollectiveのコードです。

## トップページから新規登録画面へのリンクを追加

LaravelCollectiveの`link_to_route`という関数を使ってページ推移を実装します。

```header.blade.php
<ul class="nav navbar-nav navbar-right">
   <li class="nav-item">{!! link_to_route('signup', '新規ユーザ登録', [], ['class' => 'nav-link']) !!}</li>
   <li class="nav-item"><a href="" class="nav-link">ログイン</a></li>
</ul>
```

これで、トップ画面上部の`新規ユーザ登録`クリックで、新規登録ページに推移できるようになりました。

ちなみに、新規登録画面は以下の画像のようになっているはずです。(上部が見切れていますが😅)

![スクリーンショット 2021-10-03 13.41.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1209814/853206a4-a1cd-c91a-b17b-37bcaba42819.png)

## 新規ユーザ登録をやってみよう

作成した入力フォームを使用して、新規登録します。

登録後、画面推移が上手くいかない場合は、`app/Http/middleware/RedirectIfAuthenticated.php`の該当行を変更しましょう。

```
return redirect(RouteServiceProvider::HOME);

↓

return redirect('/'); //これに変更
```

新規登録できたら、tinkerよりユーザ一覧をみてみましょう。

```
use App\User
User::all()
```

登録したユーザ情報が表示されれば、無事に登録機能が実装できています。

現時点では、ログアウト機能がありませんので、`php artisan migrate:refresh` などで、ユーザを削除し、強制ログアウトしておきましょう。

その後、新規登録画面に入りなおしましょう。

## バリデーションの動作確認

入力フォームを例えば、以下のような状態で登録しようとした時、しっかりエラーが出るか確認しましょう。

- 名前　→　空欄のとき
- Eメール　→　空欄のとき
- パスワード　→　８文字未満の時
- パスワード確認　→　パスワード欄とパスワード確認欄の内容が不一致のとき

画像のようなエラーメッセージが出ればOKです。

![スクリーンショット 2021-10-03 14.28.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1209814/f2687b06-7cbb-4504-9942-1f9a4f929f8b.png)

無事、ユーザ登録機能が実装できました！

## 第３回おわり

ここまで出来れば、あとは似たようなことの繰り返しで出来るはずです。
一緒に頑張っていきましょう！

第4回は、ログイン＆動画登録を実装していきます😄

↓第4回はこちら
[LaravelでYoutubeのお気に入りCuration(まとめ)アプリを作る【第4回: ログイン＆動画登録の実装】](https://qiita.com/dogabon20/items/d256589bcce60459f799)