フォームリクエストバリデーションを使うと簡単にバリデータを書けて楽ではあるのですが、こいつはバリデーションに失敗すると勝手に前ページにリダイレクトします。
リダイレクト先を変更する手段はありますが、止める手段がありません。
リダイレクトさせずにコントローラ側でどうこうしたいことがあったのだけど、その対応にやたら苦労したので備忘録。
試したバージョンはLaravel5.7。
ソース
フォームリクエスト
<?php
namespace App\Http\Requests;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
class FooRequest extends FormRequest
{
/**
* バリデーションルール
*
* @return array
*/
public function rules()
{
return [
'bar' => 'required',
];
}
/**
* @Override
* 勝手にリダイレクトさせない
* @param \Illuminate\Contracts\Validation\Validator $validator
*/
protected function failedValidation(Validator $validator)
{
}
/**
* バリデータを取得する
* @return \Illuminate\Contracts\Validation\Validator $validator
*/
public function getValidator()
{
return $this->validator;
}
}
リクエスト時にはまずValidatesWhenResolvedTrait::validateResolved()
が呼ばれるのだが、その中でif ($instance->fails()) { $this->failedValidation($instance); }
までべったり書かれている。
そしてFormRequest::failedValidation()
はその中でリダイレクトしている。
ここまでコントローラより先に動くので、コントローラからは手を出す手段がない。
従って、フォームリクエストでfailedValidation()
を上書きしてリダイレクトしないようにした。
次にコントローラからバリデータを取得したいのだが、フォームリクエストのValidatorはprotectedであり、さらに取得するメソッドがないのでコントローラで取り出すことができない。
従って、Validatorを取得するメソッドgetValidator()
を追加した。
コントローラ
class FooController extends Controller
{
/**
* なんかするアクション
* @param FooRequest
* @return Response
*/
public function setBar(FooRequest $request)
{
// バリデータ取得
$validator = $request->getValidator();
// 以後Validatorファサードと同じように使える
if($validator->fails()){
return redirect('hoge/fuga')
->withErrors($validator)
->withInput();
}
}
Validator::make
したときと同様にValidatorを取れるので、あとはコントローラ側で任意に操作することができる。
感想
解決策だけ見ると簡単っぽく見えるけど、当初は流儀に則ったやり方がないかを探していたらFormRequestやらValidatesWhenResolvedTraitやらValidation\Factoryやらを延々彷徨う羽目になりました。
そのうえ良さげな方法が結局見当たらなかったので、直接上書きして穴を空けるという物理的解決法になりました。
絶対もっといい方法があると思うんだけどどうなんだろう。
その他
Laravelは用意された道に沿って歩くだけなら快適だけど、ちょっとでも道を外れようとすると途端に酷道になるという印象。
今度はRoute::any('hoge\{fuga}', 'HogeController@{fuga}Action');
ってできないのか調査中。