【Laravel】ミドルウェアとは?使い方やメリット、グローバル登録の方法

この記事からわかること

  • LaravelMiddleware(ミドルウェア)とは?
  • 使い方設定方法メリット
  • ビューコンポーザとの違い
  • 実行されるタイミング
  • グローバルミドルウェアとミドルウェアのグループ化

index

[open]

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

phpのフレームワークであるLaravelの機能の1つ「Middleware(ミドルウェア)」の仕組みや設定方法、使い方など備忘録がてらまとめていきたいと思います。

公式:middleware(ミドルウェア)

Middleware(ミドルウェア)とは?

Middleware(ミドルウェア)とはLaravelに備わっているHTTPリクエストが送られたタイミングで実行される処理を定義できる機能です。

LaravelではURLにアクセス(リクエスト)があるとマッチするルーティングを検索し、そのルーティングに紐づけられているコントローラのアクションメソッドを呼び出し指定されたレスポンスを返します。

                URL(リクエスト)
                    ↓
                ルーティング
                    ↓  ⇦ ミドルウェア処理
                アクションメソッド 
                    ↓  ⇦ (orミドルウェア処理)
                レスポンス作成
                    ↓  ⇦ ビューコンポーザ処理
                レンダリング(ページ表示)

ミドルウェアはリクエストを受けてからコントローラのアクションメソッドが実行される前部分(または後部分)に処理を行わせることができます。

例えばページアクセスに認証機能を持たせる場合などそのページのレスポンスが返る前にログイン済みかを識別し、済みであればそのページを未ログインであれば別ページのリダイレクトを施すといった際にミドルウェアは力を発揮します。

Middleware(ミドルウェア)とは〜まとめ〜

ビューコンポーザとの違いとメリット

Laravelには似たような機能の「ビューコンポーザ」があります。個人的に両者の違いが分かりにくかったのでまとめてみます。

ビューコンポーザの特徴

ミドルウェアの特徴

Middleware(ミドルウェア)を使用する流れ

  1. artisanコマンドで作成
  2. 処理を記述
  3. ミドルウェアの登録
  4. ルーティングにミドルウェアを紐づける

1.artisanコマンドで作成

ミドルウェアは専用のスクリプトファイルを作成し処理を記述します。作成はartisanコマンドで行います。

$ php artisan make:middleware TestMiddleware
Middleware created successfully.

これで「app」>「Http」>「Middleware」内に「TestMiddleware.php(指定したファイル名)」が作成されます。

2.処理を記述(簡素な認証ページの作成)

今回は簡素な認証ページを作ってみます。

認証ページの仕組み

  1. 「index」ページからPOST送信
  2. ミドルウェアで値を識別
  3. 指定値なら「confirm」ページへ
  4. 指定値以外なら「welcome」ページへ

TestMiddleware.php

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class TestMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param    \Illuminate\Http\Request  $request
     * @param    \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse)  $next
     * @return  \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
     */
    public function handle(Request $request, Closure $next)
    {
        // リクエストからのPost送信された値を識別 指定値は「token」とする
        if ($request->input('token') !== 'token') {
            return redirect('/welcome');
        }

        return $next($request);
    }
}

index.blade.php

<body>
  <h1>Index</h1>
  <form action="confirm" method="post">
    @csrf
    <input type="text" name="token" value="">
    <button type="submit">送信</button>
  </form>
</body>

「confirm」ページと「welcome」ページは適当に作成して置いてください。

Laravelではフォーム実装時に@csrfを設置しないと419ページになるので注意してください。@csrfを無効にしたい場合へ飛ぶ

Laravelで表示されてしまった419(期限切れ)ページ

handleメソッド

作成されたスクリプトファイルの中身は継承もされていないシンプルなクラスです。

中にはhandleメソッドが1つ用意されておりこの中に自動実行させたい処理を記述していきます。handleメソッドRequestインスタンスを受け取る$requestとレスポンスを返す専用のClosure(関数)となっている$nextが渡されています。

Requestインスタンスがあることでこれを介してアクセスされたURLやinput要素の値などを取得できます。

$request->url();
$request->input('token');

Closure(関数)は$nextの引数にリクエストを渡すことで後続の処置にリクエストをそのまま渡すことができます。

 return $next($request);

3.ミドルウェアの登録

作成したミドルウェアは登録しないと使用できません。登録はミドルウェアを管理している「app」>「Http」>「Kernel.php」に追記していきます。$routeMiddleware配列の中に登録したいミドルウェアのパスを形式に倣って記述します。

Kernel.php

protected $routeMiddleware = [
    'auth' => \App\Http\Middleware\Authenticate::class,
    〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
    // 追記
    'test' => \App\Http\Middleware\TestMiddleware::class,
];

4.ルーティングにミドルウェアを紐づける

続いてルーティングとミドルウェアを紐づけます。「web.php」のルーティングからmiddlewareメソッドを呼び出し引数に紐づけたいミドルウェアクラスのパスを渡します。

web.php

Route::post('/confirm', 'App\Http\Controllers\appController@confirm')->middleware(\App\Http\Middleware\TestMiddleware::class);

これでミドルウェアの作成〜登録までの作業は終了です。実際に「indexページ」にアクセスしinput要素に値を入力して送信してみてください。今回は値が「token」の場合のみ「confirmページ」にアクセスできます。

ミドルウェアとグローバルミドルウェア

ミドルウェアは作成後「web.php」などのルーティングファイルの、定義されたルーティングに1つ1つ紐づけていきました

しかし例えば全てのアクセスに同じミドルウェアを実行させたい場合は1つ1つ紐づけるより「グローバルミドルウェア」として登録することで全てのルーティングにミドルウェアを紐づけることができます。

グローバルミドルウェアの登録方法

通常のミドルウェアは$routeMiddleware配列の中に登録したいミドルウェアを記述しましたが、グローバルミドルウェアとして登録する場合は$middleware配列の中に追記します。

Kernel.php

protected $middleware = [
    \App\Http\Middleware\TrustProxies::class,
    〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
    // 追記
    \App\Http\Middleware\TestMiddleware::class,
];

先ほどは以下の形式でしたがグローバルミドルウェアの場合はキー値は不要でパスのみ記述すればOKです。

'test' => \App\Http\Middleware\TestMiddleware::class,
                  ↓
\App\Http\Middleware\TestMiddleware::class,

先ほどの簡素な認証ミドルウェアをグローバルにすると全てのページにアクセスできなくなってしまう(全てのページにinput['token']の値が必要になる)ので注意してください。

ミドルウェアグループの作成

ミドルウェアクラスを複数定義して1つのルーティングに複数紐付けたい場合は「ミドルウェアグループ」を作成すると便利です。「Kernel.php」の$middlewareGroupsには最初から「web」グループと「api」グループがあります。これに倣って新しい配列を作成し中にグループ化したいミドルウェアクラスを記述します。

Kernel.php

 protected $middlewareGroups = [
    'web' => [
      // ちなみに↓この行をコメントアウトすればcsrf機能を無効にできます
      \App\Http\Middleware\VerifyCsrfToken::class,
      〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
    ],

    'api' => [
      〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
    ],

    'new' => [
      // 新しい配列を作成し中にグループ化したいミドルウェアクラスを記述する
      \App\Http\Middleware\TestMiddleware::class,
      \App\Http\Middleware\Test2Middleware::class,
      \App\Http\Middleware\Test3Middleware::class,
    ],
];

登録が完了したらルーティングからはmiddlewareメソッドの引数に登録したキー値(今回はnew)を指定するだけです。

web.php

Route::post('/confirm', 'App\Http\Controllers\appController@confirm')->middleware('new');

これでこのルーティングには紐付けたグループに列挙してあるミドルウェアクラスが全て実行されます。

ミドルウェアが動かない時の解決法

ミドルウェアが正しく動作しない場合は以下のポイントをチェックしてみてください。

ミドルウェアが動かない時のポイント

ミドルウェアから変数を渡す処理

ミドルウェアからbladeテンプレートに変数としてデータを受け渡すことも可能です。その際は以下の順番で変数を受け渡していきます。

  1. ミドルウェアクラスにデータを定義
  2. クラス内で$requestにmerge(結合)
  3. コントローラ側でmergeされた値を取得
  4. コントローラ側からbladeファイルへデータを渡す

まずはミドルウェアクラス内に変数とデータを定義→mergeメソッドを使って$requestにデータを結合します。

TestMiddleware.php

class TestMiddleware
{

    public function handle(Request $request, Closure $next)
    {
        $frameworkList = ['Laravel','CakePHP','Symfony','Zend Framework'];

        $data = ['language' => 'php', 'framework' => $frameworkList];
        $request->merge(['middleware' => $data]);
        return $next($request);
    }
}

続いてコントローラ側でリクエストにマージされているデータを設定したキー値middlewareで取得します。それを表示させるbladeテンプレートへ連想配列で渡します

appController.php

class appController extends Controller
{
    public function index(Request $request)
    {
        // mergeされているデータを取得
        $middle = $request->middleware;
        // bladeテンプレートへ連想配列で渡す
        return view('index', ['middle' => $middle]);
    }
    public function confirm(Request $request)
    {
        return view('confirm');
    }
}

これでbladeテンプレートからは以下のように渡された変数のデータにアクセスできるようになります。

index.blade.php

<body>
  <h2>ミドルウェアからの配列</h2>
  <p>{{ $middle['language'] }}</h1>
  <ul>
    @foreach ($middle['framework'] as $item)
    <li>{{$item }}</li>
    @endforeach
  </ul>
</body>
ミドルウェアからの配列
php

・Laravel
・CakePHP
・Symfony
・Zend Framework

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index