Laravelはプログラム実行において読み込むファイルの数は非常に多いです。実行速度を最適化するにはいろいろな方法がありますが、一番簡単に実行できる方法があります。遠い昔にも紹介しましたが、ルートのキャッシュです。しかし、バージョン7への更新によりちょっと問題が発生です。

ルートのキャッシュ

お客さんのプロジェクトでは、routes/web.phpapi.phpで定義されているルート(routeのことです)は結構あります。現在445あります。毎回毎回これを読み込みLaravelが処理するにはシステムに負荷がかかります。Laravelでは以前から、それを最適化してキャッシュするコマンドがあります。

まず、L7.xでプロジェクトを作成して、その時点で動作確認したところで、ルートをキャッシュしまするのですが、

その前にちょっとした作業が必要です。なぜなら、そのキャッシュのコマンドはクロージャのルートでエラーとなってしまうからです。それはL6.xでも同じことです。

ということで、以下の2つのファイルにおいてコメントアウトが必要です。

...
// 以下コメントアウト
// Route::middleware('auth:api')->get('/user', function (Request $request) {
//    return $request->user();
// });
...
// 以下コメントアウト
// Route::get('/', function () {
//    return view('welcome');
//});

Auth::routes();

Route::get('/home', 'HomeController@index')->name('home');

これでルートのキャッシュ化のコマンドを実行です。

$ php artisan route:cache
Route cache cleared!
Routes cached successfully!

成功しましたね。そしてディレクトリには以下のように、

bootstrap/cache
├── packages.php
├── routes-v7.php
└── services.php

キャッシュされたroutes-v7.phpのファイルが作成されています。L6.xではファイル名は、routes.phpでした。

重複のルート名はL6.xではOKだったのに

L7.xになってこのコマンドの実行において前バージョンから1つ変わったことあります。L6.xにおいては、ルート名の重複が許されていたのですが、L7.xではそれが許されません。比較してみましょう。

まず、L6.xの環境で、以下のようなルートの設定をします。

// Route::get('/', function () {
//     return view('welcome');
// });

// Auth::routes(); // 左の関数から以下を抽出
Route::get('login', 'Auth\LoginController@showLoginForm')->name('login');
Route::post('login', 'Auth\LoginController@login')->name('login');

// Route::get('/home', 'HomeController@index')->name('home');

Auth::routes()で設定されているルートから、loginのルート定義を取り出して、意図的にgetとpostに同じloginという名前となるように設定します。->name('login')の部分です。

$ php artisan route:list

を実行すると、

+--------+----------+-------+-------+---------------------------------------------------------+------------+
| Domain | Method   | URI   | Name  | Action                                                  | Middleware |
+--------+----------+-------+-------+---------------------------------------------------------+------------+
|        | GET|HEAD | login | login | App\Http\Controllers\Auth\LoginController@showLoginForm | web,guest  |
|        | POST     | login | login | App\Http\Controllers\Auth\LoginController@login         | web,guest  |
+--------+----------+-------+-------+---------------------------------------------------------+------------+

そして、キャッシュのコマンドの実行もOKです。

$ php artisan route:cache
Route cache cleared!
Routes cached successfully!

重複のルート名でも、GETとPOSTと使用されるメソッドが違うので使用には問題がありませんでした。

以上は、L6.xでの話ですが、L7.xでは。。。

L7.xでの問題

L7.xにおいて、先と同じようにルートをweb.phpで設定して、

$ php artisan route:list

を実行すると、

+--------+----------+-------+-------+---------------------------------------------------------+------------+
| Domain | Method   | URI   | Name  | Action                                                  | Middleware |
+--------+----------+-------+-------+---------------------------------------------------------+------------+
|        | GET|HEAD | login | login | App\Http\Controllers\Auth\LoginController@showLoginForm | web        |
|        |          |       |       |                                                         | guest      |
|        | POST     | login | login | App\Http\Controllers\Auth\LoginController@login         | web        |
|        |          |       |       |                                                         | guest      |
+--------+----------+-------+-------+---------------------------------------------------------+------------+

OKそうですね。そして、キャッシュのコマンドを実行すると、

Route cache cleared!

   LogicException 

  Unable to prepare route [login] for serialization. Another route has already been assigned name [login].
...

と、「もうloginの名前は使われているよ」というエラーが表示されます。

そうなら、重複とならないようにルートの名前を変えてみます。

...
Route::get('login', 'Auth\LoginController@showLoginForm')->name('login');
Route::post('login', 'Auth\LoginController@login')->name('login-post');
...

今度はキャッシュのコマンドの実行はOKとなりました。

$ php artisan route:cache
Route cache cleared!
Routes cached successfully!

そして、今度はpostのルートの名前を外してみます。オリジナルの定義と同じです。

...
Route::get('login', 'Auth\LoginController@showLoginForm')->name('login');
Route::post('login', 'Auth\LoginController@login');
...

これでも、キャッシュのコマンドの実行は成功となります。

どうなっているのか?と以下を実行してみると、

$ php aritsan route:list
+--------+----------+-------+-----------------------------+---------------------------------------------------------+------------+
| Domain | Method   | URI   | Name                        | Action                                                  | Middleware |
+--------+----------+-------+-----------------------------+---------------------------------------------------------+------------+
|        | GET|HEAD | login | login                       | App\Http\Controllers\Auth\LoginController@showLoginForm | web        |
|        |          |       |                             |                                                         | guest      |
|        | POST     | login | generated::Jhj05XtQrWTdgVlP | App\Http\Controllers\Auth\LoginController@login         | web        |
|        |          |       |                             |                                                         | guest      |
+--------+----------+-------+-----------------------------+---------------------------------------------------------+------------+

名が無かったルートには、 generated::Jhj05XtQrWTdgVlPと自動で名前が付けられていました。便利ですね。

最後に

ルート名がそのキャッシュ化において重複を許さなくなったL7.xの更新は、既存のコードをブレイクするという報告がいくつか出ていました。もちろんこれにより私のプロジェクトでも変更がいくつか必要となりました。ここの部分更新時には注意要です。

それから、ルートのキャッシュでもうひとつ注意することは、ルートの定義ファイルを変更したら必ず、キャッシュコマンドを再実行する必要があります。

ときどきこれを忘れてどうして変更が反映していないのか考え込んでしまう経験が過去にありました。それゆえに私の開発環境ではキャッシュせずに、本環境のみにおいてキャッシュ化を実行するようにしています。

メルマガ購読の申し込みはこちらから。

By khino