2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Laravel5.7: バリデーション(users)

Last updated at Posted at 2017-10-12

親記事

Laravel 5.7で基本的なCRUDを作る - Qiita

User用のフォームリクエストを作る

前回の記事とほぼ同じです。

PowerShell
# User用のフォームリクエストを生成
> php artisan make:request StoreUser
app/Http/Requests/StoreUser.php
    public function authorize()
    {
        // 認可は別の箇所で行うので、ここでは素通りさせる
        return true;
    }

    public function rules()
    {
        return [
            'name' => 'required|string|max:191',
            'email' => 'required|string|email|max:191|unique:users',
            'password' => 'required|string|min:6|max:191|confirmed',
        ];
    }
app/Http/Controllers/UserController.php
 // 忘れずにインポートすること!!!!
+use App\Http\Requests\StoreUser;
 
 class UserController extends Controller
 {
     /**
      * Store a newly created resource in storage.
      *
-     * @param  \Illuminate\Http\Request  $request
+     * @param  \App\Http\Requests\StoreUser $request
      * @return \Illuminate\Http\Response
      */
-    public function store(Request $request)
+    public function store(StoreUser $request)
     {

(中略)

     /**
      * Update the specified resource in storage.
      *
      * @param  \Illuminate\Http\Request  $request
      * @param  \App\User $user
      * @return \Illuminate\Http\Response
      */
     public function update(Request $request, User $user)
     {
         $this->authorize('edit', $user);
+
+        // name欄だけを検査するため、元のStoreUserクラス内のバリデーション・ルールからname欄のルールだけを取り出す。
+        $request->validate([
+            'name' => (new StoreUser())->rules()['name']
+        ]);

上のコントローラのupdateアクションでは、引数の型をStoreUserではなくRequestのままにしています。
StoreUserにすると、name欄、email欄、password欄の全てでバリデーション検査が実行されます。
しかし、現在の編集画面ではname欄しか変更できません。
name欄のみの入力値をバリデーションへ渡すと、email欄やpassword欄は空白であるとみなされ、必ず検査に失敗します。
そのため、フォームリクエスト・バリデーションに頼らず、$request->validateメソッドを使わなければなりません。
しかし、ルールを直に書くと管理が面倒なので、StoreUserのルールを流用しています。

ビューを修正する

resources/views/users/create.blade.php
         <div class="form-group">
             <label for="name">{{ __('Name') }}</label>
-            <input id="name" type="text" class="form-control" name="name" required autofocus>
+            <input id="name" type="text" class="form-control @if ($errors->has('name')) is-invalid @endif" name="name" value="{{ old('name') }}" required autofocus>
+            @if ($errors->has('name'))
+                <span class="invalid-feedback" role="alert">
+                    {{ $errors->first('name') }}
+                </span>
+            @endif
         </div>
         <div class="form-group">
             <label for="email">{{ __('E-Mail Address') }}</label>
-            <input id="email" type="email" class="form-control" name="email" required>
+            <input id="email" type="email" class="form-control @if ($errors->has('email')) is-invalid @endif" name="email" value="{{ old('email') }}" required>
+            @if ($errors->has('email'))
+                <span class="invalid-feedback" role="alert">
+                    {{ $errors->first('email') }}
+                </span>
+            @endif
         </div>
         <div class="form-group">
             <label for="password">{{ __('Password') }}</label>
-            <input id="password" type="password" class="form-control" name="password" required>
+            <input id="password" type="password" class="form-control @if ($errors->has('password')) is-invalid @endif" name="password" required>
+            @if ($errors->has('password'))
+                <span class="invalid-feedback" role="alert">
+                    {{ $errors->first('password') }}
+                </span>
+            @endif
         </div>
resources/views/users/edit.blade.php
         <div class="form-group">
             <label for="name">{{ __('Name') }}</label>
-            <input id="name" type="text" class="form-control" name="name" value="{{ $user->name }}" required autofocus>
+            <input id="name" type="text" class="form-control @if ($errors->has('name')) is-invalid @endif" name="name" value="{{ old('name', $user->name) }}" required autofocus>
+            @if ($errors->has('name'))
+                <span class="invalid-feedback" role="alert">
+                    {{ $errors->first('name') }}
+                </span>
+            @endif
         </div>

カスタム属性名を追加する

resources/lang/ja/validation.php
     'attributes' => [
         'title' => __('Title'),
         'body' => __('Body'),
+        'name' => __('Name'),
+        'email' => __('E-Mail Address'),
+        'password' => __('Password'),
     ],

Register用のルールと統合する

以前の記事で自動生成したログイン関連のファイルのうち、ユーザー登録を担当するRegisterコントローラにもUserのバリデーション・ルールが記載されています。
これを削除して、StoreUser内のルールを流用することで統一します。

app/Http/Controllers/Auth/RegisterController.php
// 忘れずにインポートすること
use App\Http\Requests\StoreUser;

    (中略)

    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:6|confirmed',
        // ]);
        // 統一したバリデーション・ルールを用いる
        return Validator::make($data, (new StoreUser())->rules());
    }

ResetPassword用のルールと統合する

パスワード再設定でも、独自のバリデーションルールが、下記のトレイトのrulesメソッドで設定されています。
:link: Illuminate\Foundation\Auth\ResetsPasswords

これをResetPasswordControllerで上書きします。
パスワードのルールのみを変更します。
メールアドレスは、対象ユーザーのメールアドレスと一致しなければどのみちエラーとなってしまうので、細かなルールに変更する必要はありません。

app/Http/Controllers/Auth/ResetPasswordController.php
// 忘れずにインポートすること
use App\Http\Requests\StoreUser;

    (中略)

    /**
     * パスワード再設定用のバリデーションルール
     *
     * @return array
     */
    protected function rules()
    {
        return [
            'token' => 'required',
            'email' => 'required|email',
            'password' => (new StoreUser())->rules()['password'],
        ];
    }

(余談) パスワードは6文字以上にすべき

6文字以上なら面倒がありません。

どういうことかと言うと、下記の場所でmb_strlen($password) >= 6とハードコーディングされていて、6文字未満に設定するのが難しいからです。
:link: Illuminate\Auth\Passwords\PasswordBroker

このハードコーディングされた箇所が実行されないようにするには、先ほどのResetPasswordControllerに下記のような追記が必要です。

app/Http/Controllers/Auth/ResetPasswordController.php
// 追加でインポート
use Illuminate\Support\Facades\Password;
use Illuminate\Http\Request;

    (中略)

    /**
     * Reset the given user's password.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
     */
    public function reset(Request $request)
    {
        $this->validate($request, $this->rules(), $this->validationErrorMessages());

        $broker = Password::broker();
        $broker->validator(function() {
            return true; // 追加のバリデーションは不要
        });
        $response = $broker->reset(
            $this->credentials($request), function ($user, $password) {
                $this->resetPassword($user, $password);
            }
        );

        return $response == Password::PASSWORD_RESET
                    ? $this->sendResetResponse($request, $response)
                    : $this->sendResetFailedResponse($request, $response);
    }

上のresetメソッドは、Illuminate\Foundation\Auth\ResetsPasswords トレイトの同名のメソッドを上書きします。
上のコードでも使っているPasswordファサードの元が、6がハードコーディングされているPasswordBrokerクラスなのです。

このようにフレームワークの奥深くにまで手を伸ばすと、メンテナンスが面倒だと思います。
たかがmb_strlen($password) >= 6を避けるだけのために…。
そういうわけで、パスワードの最小文字数は6以上にすべきだと思います。

一応、ハードコーディングしている箇所を削除してもらえるよう、要望を送りました。
https://github.com/laravel/ideas/issues/1307

2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?