【laravel】laravelにおけるミドルウェア

# 概要
ミドルウェアとはユーザーからのリクエストがコントローラーのアクションに届く前または後ろに配置されるプログラムです。
前に配置される場合はbeforeミドルウェア（以下：前処理）と呼び、後ろに配置される場合はafterミドルウェア（以下：後処理）と呼びます。

前処理ではログインしているか否かで制限をかけるようなリクエストに対する処理で、後処理はバリデーションのようなレスポンスに対する機能です。
（厳密にはバリデーションではなく、バリデーションで返されるエラー値）

このように、リクエスト時やレスポンス時にフィルタリングとしての機能を総称してミドルウェアといいます。

# ミドルウェアの作成
手作業でも作成できますがartisanコマンドを利用すれば自動で作成されます。

```:コマンド
php artisan make:middleware SampleMiddleware
```

## ディレクトリ構造
app\Http\MiddleWare内に作成されます。
Middleware内の既存のファイルについては省略します。

```:ディレクトリ
app
├─ Http
|  ├─ Middleware
|  |  ├─ SampleMiddleware.php
```

## ファイルの中身
生成されたファイルの中身は以下のようになっています。
ここの記述次第で前処理になるか後処理になるかが変わります。

Closureクラスは無名クラスを表すためのクラスです。
参考リンクにPHPマニュアルのClosureクラスを載せています。

```php:SampleMiddleware
namespace App\Http\Middleware;

use Closure;

class SampleMiddleware
{
  /**
   * Handle an incoming request.
   *
   * @param  \Illuminate\Http\Request  $request
   * @param  \Closure  $next
   * @return mixed
   */
  public function handle($request, Closure $next)
  {
      return $next($request);
  }
```

# 前処理で利用する場合
前処理の記述方法です。

```php:前処理
public function handle($request, Closure $next)
{
    // 処理を記述
    return $next($request);
}
```

```:処理イメージ
user → route → middleware → controller → view → user
```

# 後処理で利用する場合
後処理の記述方法です。

```php:後処理
public function handle($request, Closure $next)
{
    $request = $next($request)
    // 処理を記述
    return $request;
}
```


```:処理イメージ
user → route → controller → view → middleware → user
```

# ミドルウェアの登録
ミドルウェアを使用するには作成のみではなく「ミドルウェアを使用するで！」という登録が必要になります。
登録はapp\HttpにあるKernel.phpで記述します。

また、ミドルウェアは使い方によって登録の記述箇所が異なります。
使い方は3パターンに分類されます。
・全ての処理に共通して実行するミドルウェア（以下：グローバルミドルウェア）
・複数のミドルウェアをまとめて実行する場合（以下：ミドルウェアグループ）
・ミドルウェアを単体で実行する場合（以下：ルートミドルウェア）

```:ディレクトリ
app
├─ Http
|  └─ Kernel.php
```

## kernelの中身
行数が多くなるのでデフォルトで登録されているミドルウェアとコメントは割愛します。
ここでは配列または多次元配列で登録されるというのが伝われば十分かなと思います。

```php:Kernel
namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{
  protected $middleware = [
    // 中略
    \App\Http\Middleware\SampleMiddleware::class,
  ];

  protected $middlewareGroups = [
    'web' => [
      // 中略
    ],

    'api' => [
      // 中略
    ],
  ];

  protected $routeMiddleware = [
    // 中略
  ];

  protected $middlewarePriority = [
    // 中略
  ];
}

```

## グローバルミドルウェア
Kernelの$middlewareに登録します。
ここに登録されたミドルウェアは全てのアクセスで自動的に実行されます。

```php:Kernel
class Kernel extends HttpKernel
{
  protected $middleware = [
    // 中略

    // ここから
    \App\Http\Middleware\SampleMiddleware::class,
    // ここまで
  ];
}
```

## ミドルウェアグループ
Kernelの$middlewareGroupsに登録します。
1つ目の配列にグループ名を記述して、その配列の中にグループ化したいミドルウェアを登録していきます。

```php:Kernel
class Kernel extends HttpKernel
{
  protected $middlewareGroups = [
    'web' => [
      // 中略
    ],

    'api' => [
      // 中略
    ],

    // ここから（グループ）
    'sample' => [
      // ここから（ミドルウェア）
      \App\Http\Middleware\SampleMiddleware1::class,
      \App\Http\Middleware\SampleMiddleware3::class,
      \App\Http\Middleware\SampleMiddleware2::class,
      // ここまで（ミドルウェア）
    ],
    // ここまで（グループ）
  ];
}

```

## ルートミドルウェア
一般的にルートミドルウェアとは呼ばないと思いますが、段落分けのためにルートミドルウェアと仮名しました。
Kernelの$routeMiddlewareに登録します。

```php:Kernel
class Kernel extends HttpKernel
{
  protected $routeMiddleware = [
    // 中略

    // ここから
    'sample' =>
    \App\Http\Middleware\SampleMiddleware::class,
    // ここまで
  ];
}

```

# ミドルウェアの呼び出し
グローバルミドルウェアであれば全ての処理でミドルウェアが実行されるため呼び出しの設定は必要ありませんが、ミドルウェアグループやルートミドルウェアでは呼び出し処理を設定する必要があります。
記述方法はミドルウェアグループでもルートミドルウェアでも同じです。


```php:web.php
// ※ 一つのルートに対してミドルウェアを指定する場合
Route::get('test', function () {
  return view('test.index')
})->middleware('sample');

// ※ １つのルートに対して複数のミドルウェアを指定する場合
Route::get('test', function () {
  return view('test.index')
})->middleware('sample1', 'sample2');

// ※ 複数のルートに対して１つのミドルウェアを指定する場合
Route::group(['middleware' => 'sample'], function () {
  Route::get('test', function() {
      return view('test.index');
  });
  // 以下省略
});

// ※ 複数のルートに対して複数のミドルウェアを指定する場合
Route::group(['middleware' => ['sample1', 'sample2'], function () {
  Route::get('test', function() {
      return view('test.index');
  });
  // 以下省略
});

// もしくは
Route::middleware(['sample1', 'sample2'])->group(function () {
  Route::get('test', function() {
      return view('test.index');
  });
  // 以下省略
});
```

# 参考
[Laravel 6.x ミドルウェア](https://readouble.com/laravel/6.x/ja/middleware.html)
[Laravel 6.x ミドルウェアについて](https://laraweb.net/practice/1396/)
[PHP Crosureクラス](https://www.php.net/manual/ja/class.closure.php)