【Laravel】Closure $next, …$guardsとは何か?ファイルの場所や処理内容

laravel-prograshi(プロぐらし) Laravel
記事内に広告が含まれていることがあります。
[PR]

Laravelの認証処理の中の処理など「Closure $next, ...$guards」という記述が出てくることがあります。

この「Closure $next, …$guards」とは何なのか?「$next」や「…$guards」「guards」とは何か、それぞれどのような処理をしているのかについてまとめています。


結論:Closure $next, …$guardsとは何か?

結論からいうと、Closure $nextはClosureクラスで無名関数$nextを作成。

...$guards...は渡された複数のデータ(数に指定なし)を変数$guardsとして渡すという意味。


登場する場所

Closure $next, ...$guardsは認証処理用のミドルウェアRedirectIfAuthenticated.phpに記述されている。

App > Http > Middleware > RedirectIfAuthenticated.php

<?php

namespace App\Http\Middleware;

use App\Providers\RouteServiceProvider;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class RedirectIfAuthenticated
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @param  string|null  ...$guards
     * @return mixed
     */
    public function handle(Request $request, Closure $next, ...$guards)
    {
        $guards = empty($guards) ? [null] : $guards;

        foreach ($guards as $guard) {
            if (Auth::guard($guard)->check()) {
                return redirect(RouteServiceProvider::HOME);
            }
        }

        return $next($request);
    }
}



もう少し細かく見ると、
(1)ルーティングでmiddlewareのguestが指定される。

Route::get('/login', [AuthenticatedSessionController::class, 'create'])
                ->middleware('guest')
                ->name('login');


(2) ミドルウェアのguestはKernel.phpの中でグローバル登録されている。

    protected $routeMiddleware = [
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
    ];


(3) ミドルウェアguestで\App\Http\Middleware\RedirectIfAuthenticatedが実行される。

このRedirectIfAuthenticatedの中の処理となる。


$nextとは何か?

Closure $next

Clouserクラス

無名関数を作るクラス。
関数の引数の中でClosure 変数名とすることで、無名関数のインスタンスを指定した変数名で作成する。(依存注入)


$next

無名関数のインスタンスが入った変数。middlewareの処理でのみ登場する。

処理結果をコントローラに渡す。

    public function handle(Request $request, Closure $next, ...$guards)
    {
        $guards = empty($guards) ? [null] : $guards;

        foreach ($guards as $guard) {
            if (Auth::guard($guard)->check()) {
                return redirect(RouteServiceProvider::HOME);
            }
        }

        return $next($request);
    }


…$guardsとは何か?

こちらもhandle関数の引数で渡されているデータ。

...は可変長引数。任意の数だけ引数を渡すことができる。

通常は一つの引数に対して一つのデータが渡された順に入っていく。可変長引数にすると、入力したデータをすべて渡すことができる。(引数の数が合わない!というエラーが出ない)

変数$guardsはphp doc(説明文)を見ると、文字列か空とのこと。

* @param  string|null  ...$guards


guardsとは何か?

Laravelのguard(ガード)とは、各リクエスト毎にどのようにユーザーを認証するかを定義したもの。

config > auth.php の中で定義されている。

    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'api' => [
            'driver' => 'token',
            'provider' => 'users',
            'hash' => false,
        ],
    ],

通常のブラウザ経由での認証の場合はwebを参照する。

'driver' => 'session'
認証状況のデータの受け渡しはセッションを使用。(APIの場合はセッション情報ではなくトークンを使う)

'provider' => 'users',
認証状況の照合にはusersテーブル(userモデル)を使用する。


handle関数の処理内容

変数guards

$guards = empty($guards) ? [null] : $guards;

これは三項演算子による書き方。

条件式 ? 式1 : 式2

//$guardsが空の場合(次のforeach処理でエラーが出ないようにする)
$guards=[null]

//$guards`が空でない
$guards = $guards

ここでは$guardsはconfig > auth.php の中で定義されている内容が入る。(nullではない)

    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'api' => [
            'driver' => 'token',
            'provider' => 'users',
            'hash' => false,
        ],
    ],


認証状況の判断

Auth::guard('ガード名')

Authファサードのguardメソッドでガード名を指定することで、指定したガードを呼び出す。

ここでは、webとapiが順番に呼び出される

checkメソッド
ユーザーが既にログインしているかを調べる。

        foreach ($guards as $guard) {
            if (Auth::guard($guard)->check()) {
                return redirect(RouteServiceProvider::HOME);
            }
        }

ユーザーが既にログインしている場合は、RouteServiceProviderクラスの定数HOMEで指定したページにリダイレクトする。

Providers > RouteServiceProvider.php に記述がある。

class RouteServiceProvider extends ServiceProvider
{
    public const HOME = '/dashboard';

つまり、既にログイン済み(認証済み)であれば/dashboardページが開く。


ログイン済みでない場合

無名関数のnextで、次のミドルウェアにHTTPリクエストが渡される。

        return $next($request);


タイトルとURLをコピーしました