Twitter Facebook github

Laravel 5.2 で withErrors が動作しない時は

かなりハマって悔しかったので備忘録。

現象

LaravelのAuth周りを使ってログイン機能を実装中、ログイン失敗時のフラッシュメッセージとして動かす予定だった withErrors が正常に動かない現象が起こりました。
具体的には AuthenticatesUsers クラスにある sendFailedLoginResponse メソッドがコールされたとき、ログイン失敗を示すメッセージがリダイレクト後のページで取得できず、
$errors 変数にはデータバッグは存在するものの、値が空の状態になりました。

結論

先に結論を書くと、webミドルウェアが二重適用していたことが原因でした。

php artisan route:list を実行すると定義されているルーティング一覧を確認できますが、
そのミドルウェア欄には web,web,auth のように web が二度呼ばれていることが分かりました。

これは、ルーティングを定義する際、どこかのブログで web ミドルウェアを定義しないとセッションが扱えないといった趣旨の記事を読み、 routes.php の一番外側にwebミドルウェアを適用するようルーティングしていたのが悪かったようです。

今回は、上のファイルで3行目と10行目を削除し、webミドルウェアを外すことで二重適用を回避し、正常に動作するようになりました。

どこで web ミドルウェアが適用されていたのか

各コントローラーのコンストラクタなどでもミドルウェアの適用が可能なことは知っていましたが、どうやらLaravel 5.2ではデフォルトで web ミドルウェアが適用された状態になっていたようです。

routes.php を呼び出す際に、その外側で既にラップされてるのではないか?とあたりをつけて横断検索してみたところ、
App\Providers\RouteServiceProvider.php の mapWebRoutes メソッドで routes.php がロードされていることが分かり、同時に routes.php 全体に対して web ミドルウェアが適用されていました。

mapWebRoutes の実装は次のとおりです。

これ以外の原因

セッションがそもそも維持できていない

まずはセッションが正しく維持されているかテストすることで大きく切り分けできるかと思います。

今回は AuthenticatesUsers を継承したコントローラーで sendFailedLoginResponse メソッドをオーバーライドして、リダイレクト前に \Sesson::put('test', 'xxx'); を行い、ログイン画面のビューで var_dump(Session::get('test')); することで原因切り分けを行いました。

セッションが維持できていない場合は、 .env でセッションストアの設定が誤っていないかどうかやクッキーの設定、ファイルストアの場合はディレクトリのパーミッション等を確認します。

また、 web ミドルウェアグループの StartSession ミドルウェアが正しくロードされていない可能性があるかもしれません。

ShareErrorsFromSession ミドルウェアが有効でない

withErrors は ShareErrosFromSession ミドルウェアによって提供されているようで、このミドルウェアがロードされていないとそもそも機能が利用できません。
Laravel 5.2 では、Kernel.php で web ミドルウェアグループの一部としてデフォルトでロードされるようになっていますが、過去バージョンからのアップグレードや、自分でカスタムして手を入れた場合は要注意です。

所感

最近忙しくアウトプットがご無沙汰になっています。Laravelを使い始めて数週間経ちますが、思った以上に完成度が高く、人気になる理由がよく分かります。
ドキュメントだけで言えばCakePHPの方が圧倒的に取っ付き安いのですが、コードがとても綺麗で読みやすく、ある程度PHPの経験があればドキュメントいらずで開発を進められるように思います。日本でも流行るといいですね。

コメントを残す

メールアドレスが公開されることはありません。