【Laravel】ミドルウェア

こちらの記事は以下の書籍を参考に執筆しました

- [PHPフレームワークLaravel入門 第2版](https://www.amazon.co.jp/PHP%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AFLaravel%E5%85%A5%E9%96%80-%E7%AC%AC2%E7%89%88-%E6%8E%8C%E7%94%B0-%E6%B4%A5%E8%80%B6%E4%B9%83/dp/4798060992/ref=tmm_hrd_title_0?_encoding=UTF8&qid=1595991312&sr=1-2)



#ミドルウェアの利用
##ミドルウェアとは
指定のアドレスにリクエストが送られたら何らかの処理を行う仕組みのこと

```
/***************************/
//リクエスト
/***************************/

↓     ←ミドルウェア

/***************************/
//アクション
/***************************/

↓     ←ミドルウェア

/***************************/
//レスポンス
/***************************/
```
>出典：[PHPフレームワークLaravel入門 第2版](https://www.amazon.co.jp/PHP%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AFLaravel%E5%85%A5%E9%96%80-%E7%AC%AC2%E7%89%88-%E6%8E%8C%E7%94%B0-%E6%B4%A5%E8%80%B6%E4%B9%83/dp/4798060992/ref=tmm_hrd_title_0?_encoding=UTF8&qid=1595991312&sr=1-2)


##ミドルウェアの作成

```
php artisan make:middleware ミドルウェア名
```

これで`Http／Middleware`に作成される。
ここではHelloMiddlewareという名前で作る。

##HelloMiddlewareクラス
作成されたHelloMiddlewareはなんのクラスも継承していない。

###handleメソッドについて
これには1つだけメソッドがある。
以下のように定義されている。

```php5
    public function handle($request, Closure $next)
    {
        //実行する処理
    }
```

|引数|説明|
|---|---|
|$request|リクエスト情報を管理するRequestインスタンス|
|$next|Closureクラスのインスタンス。|
>出典：[PHPフレームワークLaravel入門 第2版](https://www.amazon.co.jp/PHP%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AFLaravel%E5%85%A5%E9%96%80-%E7%AC%AC2%E7%89%88-%E6%8E%8C%E7%94%B0-%E6%B4%A5%E8%80%B6%E4%B9%83/dp/4798060992/ref=tmm_hrd_title_0?_encoding=UTF8&qid=1595991312&sr=1-2)

Closureは無名関クラスを表すクラス。
$nextはクロージャでこれを呼び出して実行すると
ミドルウェアからアプリケーションへと送られるリスエスト(Requestインスタンス)を作成できる。

###$request->merge(配列)
```php5
public function handle($request, Closure $next)
    {
        $data=[
          ['name'=>'taro','mail'=>'taro@example.com'],
          ['name'=>'taro2','mail'=>'taro2@example.com'],
          ['name'=>'taro3','mail'=>'taro@3example.com'],
        ];
        $request->merge(['data'=>$data]);
        return $next($request);
    }
```
>出典：[PHPフレームワークLaravel入門 第2版](https://www.amazon.co.jp/PHP%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AFLaravel%E5%85%A5%E9%96%80-%E7%AC%AC2%E7%89%88-%E6%8E%8C%E7%94%B0-%E6%B4%A5%E8%80%B6%E4%B9%83/dp/4798060992/ref=tmm_hrd_title_0?_encoding=UTF8&qid=1595991312&sr=1-2)

mergeはフォーム送信で送られる値(input値)に値を追加できる。
dataという項目で\$dataの内容が追加される。
コントローラ側では`$request->data`で取り出せる。

その後ミドルウェアを登録する。
$routeMiddleware変数の最後に追記する。

```php5:app/Http/Kernel.php
'hello'=>\App\Http\Middleware\HelloMiddleware::class,
```
>出典：[PHPフレームワークLaravel入門 第2版](https://www.amazon.co.jp/PHP%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AFLaravel%E5%85%A5%E9%96%80-%E7%AC%AC2%E7%89%88-%E6%8E%8C%E7%94%B0-%E6%B4%A5%E8%80%B6%E4%B9%83/dp/4798060992/ref=tmm_hrd_title_0?_encoding=UTF8&qid=1595991312&sr=1-2)

これで登録完了。

##ミドルウェアの実行
次は利用するミドルウェアを呼び出す処理を書いていく。

```php5:web.php
//use App\Http\Middleware\HelloMiddleware;を追記
Route::get('hello', 'HelloController@index')->middleware(HelloMiddleware::class);
```
>出典：[PHPフレームワークLaravel入門 第2版](https://www.amazon.co.jp/PHP%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AFLaravel%E5%85%A5%E9%96%80-%E7%AC%AC2%E7%89%88-%E6%8E%8C%E7%94%B0-%E6%B4%A5%E8%80%B6%E4%B9%83/dp/4798060992/ref=tmm_hrd_title_0?_encoding=UTF8&qid=1595991312&sr=1-2)

メソッドチェーンで追加していく。
連続して書くこともできる。

```php5
Route::get(...)->middleware(...)->middleware(...);
```
>出典：[PHPフレームワークLaravel入門 第2版](https://www.amazon.co.jp/PHP%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AFLaravel%E5%85%A5%E9%96%80-%E7%AC%AC2%E7%89%88-%E6%8E%8C%E7%94%B0-%E6%B4%A5%E8%80%B6%E4%B9%83/dp/4798060992/ref=tmm_hrd_title_0?_encoding=UTF8&qid=1595991312&sr=1-2)


##ビューとコントローラの修正
これでミドルウェアが/helloで動作するようになった。
次は変数\$dataの動作を確認していく。

コントローラを修正する。

```php5
    public function index(Request $request)
    {
      return view('hello.index',['data'=>$request->data]);
    }
```
>出典：[PHPフレームワークLaravel入門 第2版](https://www.amazon.co.jp/PHP%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AFLaravel%E5%85%A5%E9%96%80-%E7%AC%AC2%E7%89%88-%E6%8E%8C%E7%94%B0-%E6%B4%A5%E8%80%B6%E4%B9%83/dp/4798060992/ref=tmm_hrd_title_0?_encoding=UTF8&qid=1595991312&sr=1-2)

テンプレを修正する。

```php5
@section('content')
<p>ここが本文のコンテンツ</p>  
<table>
  @foreach($data as $item)
  <tr>
    <th>{{$item['name']}}</th><td>{{$item['mail']}}</td>
  </tr>
  @endforeach
</table>
@endsection
```
>出典：[PHPフレームワークLaravel入門 第2版](https://www.amazon.co.jp/PHP%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AFLaravel%E5%85%A5%E9%96%80-%E7%AC%AC2%E7%89%88-%E6%8E%8C%E7%94%B0-%E6%B4%A5%E8%80%B6%E4%B9%83/dp/4798060992/ref=tmm_hrd_title_0?_encoding=UTF8&qid=1595991312&sr=1-2)


/helloにアクセスして確認してみる。

今後DBを使うようになるとミドルウェアがコントローラの負担を減らしてくれる。

##リクエストとレスポンスの流れ
今回は「リクエスト」→「処理」の流れだったが
「処理」→「リクエスト」もできる。
つまりアクション後の処理も作成できる。

ミドルウェアのhandleメソッドのデフォルトはこうなっていた。

```php5
    public function handle($request, Closure $next)
    {
        return $next($request);
    }
```
>出典：[PHPフレームワークLaravel入門 第2版](https://www.amazon.co.jp/PHP%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AFLaravel%E5%85%A5%E9%96%80-%E7%AC%AC2%E7%89%88-%E6%8E%8C%E7%94%B0-%E6%B4%A5%E8%80%B6%E4%B9%83/dp/4798060992/ref=tmm_hrd_title_0?_encoding=UTF8&qid=1595991312&sr=1-2)

引数として\$requestが渡され、クロージャの戻り値がreturnで返されていた。
この$nextで返されるものは**Responseインスタンス**だ。
リスエストが送られてからクライアントにレスポンスが返されるまでの流れはこうだ。

1. リクエストが送られる。
2. ミドルウェアのhandleが呼びだされる
3. $nextを実行する。複数のミドルウェアが設定されてるなら、次のミドルウェアのhandleが呼び出される。ないならコントローラのアクションが呼び出される。
4. アクションメソッドが終わるとともにページがレンダリングされ、レスポンスが生成される。この生成されたレスポンスが$nextの戻り値。
5. 返されたレスポンスがreturnで返され、クライアントへ返される。

###前処理と後処理
この流れを理解するとコントローラの前と後でのミドルウェアの作成方法がわかる。

####前処理
先もやったように、必要な処理をすべて実行してから$nextを実行してreturn

```php5
    public function handle($request, Closure $next)
    {
        //処理を実行
        return $next($request);
    }
```
>出典：[PHPフレームワークLaravel入門 第2版](https://www.amazon.co.jp/PHP%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AFLaravel%E5%85%A5%E9%96%80-%E7%AC%AC2%E7%89%88-%E6%8E%8C%E7%94%B0-%E6%B4%A5%E8%80%B6%E4%B9%83/dp/4798060992/ref=tmm_hrd_title_0?_encoding=UTF8&qid=1595991312&sr=1-2)


####後処理
$nextを実行してレスポンスを受け取ってから処理を実行する。
処理が終わったら保管してあったレスポンスをreturn

```php5
    public function handle($request, Closure $next)
    {
        $response=$next($request)
        //処理を実行
        return $response;
    }
```>出典：[PHPフレームワークLaravel入門 第2版](https://www.amazon.co.jp/PHP%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AFLaravel%E5%85%A5%E9%96%80-%E7%AC%AC2%E7%89%88-%E6%8E%8C%E7%94%B0-%E6%B4%A5%E8%80%B6%E4%B9%83/dp/4798060992/ref=tmm_hrd_title_0?_encoding=UTF8&qid=1595991312&sr=1-2)


##レスポンス操作
では後処理のサンプルを作っていく。
HelloMiddlewareクラスを修正

```php5
    public function handle($request, Closure $next)
    {
        $response = $next($request);
        $content  = $response->content();
        $pattern  = '/<middleware>(.*)<\/middleware>/i';
        $replace  = '<a href="http://$1">$1</a>';
        $content  = preg_replace($pattern, $replace, $content);
        $response->setContent($content);
        return $response;
    }
```
>出典：[PHPフレームワークLaravel入門 第2版](https://www.amazon.co.jp/PHP%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AFLaravel%E5%85%A5%E9%96%80-%E7%AC%AC2%E7%89%88-%E6%8E%8C%E7%94%B0-%E6%B4%A5%E8%80%B6%E4%B9%83/dp/4798060992/ref=tmm_hrd_title_0?_encoding=UTF8&qid=1595991312&sr=1-2)


###処理の流れ
```php5
$response = $next($request);
```
>出典：[PHPフレームワークLaravel入門 第2版](https://www.amazon.co.jp/PHP%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AFLaravel%E5%85%A5%E9%96%80-%E7%AC%AC2%E7%89%88-%E6%8E%8C%E7%94%B0-%E6%B4%A5%E8%80%B6%E4%B9%83/dp/4798060992/ref=tmm_hrd_title_0?_encoding=UTF8&qid=1595991312&sr=1-2)

でコントローラのアクションが実行され、レスポンスが代入される。

```php5
$content  = $response->content();
```
>出典：[PHPフレームワークLaravel入門 第2版](https://www.amazon.co.jp/PHP%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AFLaravel%E5%85%A5%E9%96%80-%E7%AC%AC2%E7%89%88-%E6%8E%8C%E7%94%B0-%E6%B4%A5%E8%80%B6%E4%B9%83/dp/4798060992/ref=tmm_hrd_title_0?_encoding=UTF8&qid=1595991312&sr=1-2)

コンテンツを取得している。
その後正規表現で置換を行っている。
後はレスポンスにコンテンツを設定してreturn

```php5
$response->setContent($content);
return $response;
```
>出典：[PHPフレームワークLaravel入門 第2版](https://www.amazon.co.jp/PHP%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AFLaravel%E5%85%A5%E9%96%80-%E7%AC%AC2%E7%89%88-%E6%8E%8C%E7%94%B0-%E6%B4%A5%E8%80%B6%E4%B9%83/dp/4798060992/ref=tmm_hrd_title_0?_encoding=UTF8&qid=1595991312&sr=1-2)

レスポンスへのコンテンツの設定には**setContent**メソッドを使う。


つぎはテンプレを修正

```php5:index.blade.php
@section('content')
  <p>ここが本文のコンテンツ</p>  
  <p>これは<middleware>google.com</middleware></p>
  <p>これは<middleware>yahoo.co.jp</middleware></p>
@endsection
```
>出典：[PHPフレームワークLaravel入門 第2版](https://www.amazon.co.jp/PHP%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AFLaravel%E5%85%A5%E9%96%80-%E7%AC%AC2%E7%89%88-%E6%8E%8C%E7%94%B0-%E6%B4%A5%E8%80%B6%E4%B9%83/dp/4798060992/ref=tmm_hrd_title_0?_encoding=UTF8&qid=1595991312&sr=1-2)

コントローラの修正

```php5
    public function index(Request $request)
    {
      return view('hello.index');
    }
```
>出典：[PHPフレームワークLaravel入門 第2版](https://www.amazon.co.jp/PHP%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AFLaravel%E5%85%A5%E9%96%80-%E7%AC%AC2%E7%89%88-%E6%8E%8C%E7%94%B0-%E6%B4%A5%E8%80%B6%E4%B9%83/dp/4798060992/ref=tmm_hrd_title_0?_encoding=UTF8&qid=1595991312&sr=1-2)


今回はコントロー側では何もしていない。
では、/helloにアクセスして確かめる。