こんにちは!
この間laravelでファイルアップロード処理を含む保存処理のバリデーションの実装をしていたときに、バリデーションエラー時にアップロードしたファイルのデータがなくなってしまうので、ファイルアップロード以外のバリデーションエラー時にアップロードしたファイルを仮アップロードしてからリダイレクトという実装をしました。
まぁカスタムバリデートを実装すればいいことですが、フォームリクエストバリデーションの中でアップロードの処理をするのも変な感じがするし、かと言ってコントローラにValidatorのロジックを書くとコントローラ内が冗長になるし、アクションごとにフォームリクエストバリデーションとコントローラでのバリデーションを切り替えるのも気持ちが悪い
なんかなるべく共通した書き方できないかなーと感じて個人的にしっくりきた書き方を紹介したいと思います!
結論を先に書くとバリデーションクラスを作ってValidatorインスタンスを返す処理を実装します
コードはユーザーの名前とアイコン画像の編集を実装すると仮定します
route
Route::post('user/update', 'UserController@update')->name('user.update');
view
<form action="{{route('user.update')}}" method="post" enctype="multipart/form-data">
@csrf
<input type="text" name="name">
<input type="file" name="file">
</form>
Validator
<?php
namespace App\Http\Validator;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
class UserValidator
{
public function createValidation(Request $request): \Illuminate\Contracts\Validation\Validator
{
$params = $request->all();
return Validator::make($params, [// <- バリデーターインスタンスを返す
'name' => [
'required',
],
'file' => [
'file',
'image',
'mimes:jpeg,jpg,png,gif',
'max:5120',
],
], [
'name' => '入力されていません。',
'file.file' => '不正なファイルです。',
'file.image' => '画像以外のデータが送信されました。',
'file.mimes' => '登録できる拡張子はjpeg,jpg,png,gifのいずれかになります。',
'file.max' => '画像サイズが大きすぎます。',
])->after(function ($validator) use ($params) {
//...カスタムバリデーション
$validator->errors()->add('name', 'エラー!');
});
}
}
controller
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Validator\UserValidator;
class UserController extends Controller
{
privare $userValidator;
public function __construct(UserValidator $userValidator)
{
$this->userValidator = $userValidator;
}
public function update(Request $request)
{
$validator = $this->userValidator->updateValidation($request);
$validator->validate();//@todo バリデーションエラー時に即リダイレクト
//or
if ($validator->fails()) {
//@todo バリデーションに引っかかったフィールド名を取得(ここもっと分かり易いやり方方法ないのかな?)
$messageBag = $validator->messages();
$error_messages = $messageBag->getMessages();
if (!array_key_exists('file', $error_messages)) {
//@todo nameフィールドでバリデート引っかかったけどfileフィールドは通過した時の処理(仮ファイルアップロードの処理など)
//...
}
//@todo バリデーションエラーと入力したデータを持ってリダイレクト
return redirect()
->route('user.edit')
->withErrors($validator)
->withInput();
}
//@todo バリデーション通過時の処理
...
return redirect()->route('user.edit');
}
}
こうすれば即リダイレクトと処理を挟んでリダイレクトが簡単に切り替えられるし、そこまで冗長じゃないし、あと他の人がコントローラを見たとき何がしたいのかよくわかるのかなーと
まぁsymfonyのhandleRequestに近づけた感じです
参考にしてください!