【Laravel7でユーザー認証_3】ユーザー認証をメールアドレスからユーザー名に変更する

# はじめに
Laravel7で作成したユーザー認証は、メールアドレスとパスワードを使ってログインしますが、これをユーザー名とパスワードに変更する方法についてまとめます。

- ユーザー名は、「username」というカラムを新たに作成する。
- username は半角英数とハイフン、アンダーバーのみ許可する。
- username は必須項目とし、一意のものとする。
- 入力可能文字長は1文字～32文字以内とする。

# 環境
XAMPP環境でLaravelが使えるように設定してあります。

Windows10 Pro 64bit
PHP 7.3.18
Laravel 7.12.0
MariaDB 10.1.32

また、Laravelプロジェクトは以下の手順で、ユーザー認証を日本語化してあります。

- [【Laravel7でユーザー認証_1】基本のき](https://qiita.com/crosawassant/items/bf3982666b6333bcb8c8)
- [【Laravel7でユーザー認証_2】ユーザー認証を日本語化](https://qiita.com/crosawassant/items/d1f4c5c93f30afa9eb65)

# usersテーブルにusernameを追加

Usersテーブルにユーザー名のカラムを増やすためのマイグレーションファイルを作成します。

```
$ php artisan make:migration add_username_to_users --table=users
```

`database/migrations` の中にマイグレーションファイルが作成されるので、`username`カラムを追加する内容を記入します。

```diff:database/migrations/日付_add_username_to_users.php
      /**
       * Run the migrations.
       *
       * @return void
       */
      public function up()
      {
          Schema::table('users', function (Blueprint $table) {
-             //
+             //文字長32、ユニーク制約、idカラムの直後に追加、コメント「ユーザー名」でusernameカラム追加
+             $table->string('username', 32)->unique('users_username_unique')->after('id')->comment('ユーザー名');
          });
      }

      /**
       * Reverse the migrations.
       *
       * @return void
       */
      public function down()
      {
          Schema::table('users', function (Blueprint $table) {
-             //
+             $table->dropColumn('username');
          });
      }
```

データベースに反映させます。

```
$ php artisan migrate
```

![Laravel-username-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262236/50815b65-affc-844f-c754-32501ac4bca8.png)

`username` カラムが追加されました。


# 新規登録にユーザー名の項目を追加する

ユーザーの登録時に、ユーザー名の入力が必須になるよう修正します。

## viewの変更

登録画面に、ユーザー名の入力を追加します。
今回はパスワードの上に項目を追加しました。

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

  @section('content')
  <div class="container">

 ～～～（略）～～～

                          <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="name" class="col-md-4 col-form-label text-md-right">ユーザー名</label>
+
+                             <div class="col-md-6">
+                                 <input id="username" type="text" class="form-control @error('username') is-invalid @enderror" name="username" value="{{ old('username') }}" required autocomplete="username">
+
+                                 @error('username')
+                                     <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>
```

翻訳文字列 `{{ __('UserName') }}` について、`resources/lang/ja.json` に追加します。
（日本語化について → [【Laravel7でユーザー認証_2】ユーザー認証を日本語化](https://qiita.com/crosawassant/items/d1f4c5c93f30afa9eb65)）

```diff:resources/lang/ja.json
 {
+    "UserName": "ユーザー名",
     "Register": "ユーザー登録",
     "Name": "氏名",
```

## Userモデルの変更

Userモデルに、usernameを追加します。

```diff:app/User.php
     /**
      * The attributes that are mass assignable.
      *
      * @var array
      */
     protected $fillable = [
-        'name', 'email', 'password',
+        'name', 'email', 'password', 'username',
     ];
```

## コントローラーの変更

ユーザー登録のコントローラーファイルに、usernameのバリデーションルールと登録処理を追加します。

```diff:app/Http/Controllers/Auth/RegisterController.php


     /**
      * 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, [
             'name' => ['required', 'string', 'max:255'],
             'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
             'password' => ['required', 'string', 'min:8', 'confirmed'],
+            'username' => ['required', 'string', 'max:32', 'unique:users', 'regex:/^[a-zA-Z0-9-_]+$/],
         ]);
     }

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

```

ここまででできたら、一旦登録ができるか試してみます。
半角英数以外の文字列を入力して、バリデーションエラーが表示されるかどうかも確認します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262236/ac408fc6-f6d3-c544-66a6-127a9a7539b4.png" width="600">


全角文字を入力してみると、「usernameに正しい形式を入力してください」と表示されるので、`resources/lang/ja/validation.php` のカスタムバリデーション属性名にusernameを追加します。
（日本語化について → [【Laravel7でユーザー認証_2】ユーザー認証を日本語化](https://qiita.com/crosawassant/items/d1f4c5c93f30afa9eb65)）

```diff:resources/lang/ja/validation.php
     /*
     |--------------------------------------------------------------------------
     | カスタムバリデーション属性名
     |--------------------------------------------------------------------------
     |
     | 以下の言語行は、例えば"email"の代わりに「メールアドレス」のように、
     | 読み手にフレンドリーな表現でプレースホルダーを置き換えるために指定する
     | 言語行です。これはメッセージをよりきれいに表示するために役に立ちます。
     |
     */

     'attributes' => [
       "name" => "氏名",
       "email" => "メールアドレス",
       "password" => "パスワード",
       "password_confirmation" => "パスワード(確認用)",
+      "username" => "ユーザー名",
     ],
```

登録が問題なく出来たら、次はログイン部分を変更します。

# ログインに必要な項目をメールアドレスからユーザー名に変更する

## viewの変更

ログイン画面で入力する項目として、メールアドレスからユーザー名に変更します。

```diff:resources/views/auth/login.blade.php
                      <form method="POST" action="{{ route('login') }}">
                          @csrf
  
                         <div class="form-group row">
-                             <label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>
+                             <label for="email" class="col-md-4 col-form-label text-md-right">{{ __('UserName') }}</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" autofocus>
+                                 <input id="username" type="username" class="form-control @error('username') is-invalid @enderror" name="username" value="{{ old('username') }}" required autocomplete="username" autofocus>
- 
-                                 @error('email')
+                                 @error('username')

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

```


## コントローラーの変更

ログイン機能のコントローラーについて、`username()`という関数を追加します。
もし、ログインに使いたいカラム名が `userid` や `loginname` だった場合は、関数名は `username()` のままで、returnで返る値についてを各カラム名に変更します。

```diff:app/Http/Controllers/Auth/LoginController.php
      /**
       * Create a new controller instance.
       *
       * @return void
       */
      public function __construct()
      {
          $this->middleware('guest')->except('logout');
      } 
+  
+     public function username()
+     {
+       return 'username';
+     }

  }

```

以上の作業で、ユーザー名とパスワードでログインできるようになります。


# 参考サイト
- [PHPフレームワーク『Laravel』入門 #7 ログイン機能とカスタマイズ方法](https://knowledge.cpi.ad.jp/howto-cpi/laravel-login/)