配列値の入力、つまり複数行に同じ入力項目を持つフォームの話です。お客様の登録などのフォームとは違って、バリデーションや画面でのエラーの表示など複雑な部分が多いです。しかし、コントローラで対応するより、FormRequestを使うとすっきりしたコードとなります。
配列値の入力フォーム
各行の入力項目が1つのケースから作成してみます。以下のような画面です。行数は固定で、最大3つまでのメールアドレスの入力が可能です。
コントローラのコードは、極力シンプルにして、投稿が成功したらバリデートした値を出力します。
namespace App\Http\Controllers;
use App\Http\Requests\EmailsRequest;
use Illuminate\Http\Request;
class FormController extends Controller
{
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
return view('form');
}
/**
* Store a newly created resource in storage.
*
* @param App\Http\Requests\EmailsRequest $request
* @return \Illuminate\Http\Response
*/
public function store(EmailsRequest $request)
{
ddd($request->validated());
}
}
ブレードは、
...
<div class="container-fluid">
<div class="row">
<div class="col-md-12 col-lg-12 mt-2">
<div class="card card-primary">
<div class="card-header">
<h3 class="card-title">複数行のフォーム</h3>
</div>
<form method="POST" action="{{ route('form.store') }}" class="form-horizontal" novalidate="">
@csrf
<div class="card-body">
@error('emails')
<div class="invalid-feedback d-block">{{ $message }}</div>
@enderror
<div class="table-responsive">
<table class="table table-bordered table-hover table-sm">
<thead>
<tr>
<th>メールアドレス</th>
</tr>
</thead>
<tbody>
@for ($i = 0; $i < 3; $i++)
<tr>
<td>
<input class="form-control" maxlength="255" name="emails[]" type="text" value="{{ old('emails.'.$i) }}">
@error('emails.'.$i)
<span class="invalid-feedback d-block">{{ $message }}</span>
@enderror
</td>
</tr>
@endfor
</tbody>
</table>
</div>
</div>
<div class="card-footer">
<button class="btn btn-primary float-right mr-2" type="submit">保存</button>
</div>
</form>
</div><!-- card -->
</div>
</div><!-- row -->
</div>
...
そして、FormRequestは、
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class EmaisRequest extends FormRequest
{
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'emails.*' => 'nullable|email|distinct', // nullableとしているのは空行を許すため
];
}
public function messages()
{
return [
'emails.*.email' => '不正なメールです',
'emails.*.distinct' => '重複の入力があります'
];
}
}
実際に入力するとエラーはこんな感じで出力されます。
そしてバリデートされた値はこんな感じです。
しかし、これではDBに保存するときにいちいちnullを外す必要ありますね。これもFormRequestで処理したいです。
入力値の加工
FormRequestで入力値を加工するには、以下のようにprepareForValidation()を追加して処理します。
...
class EmailsRequest extends FormRequest
{
protected function prepareForValidation()
{
$emails = collect($this->emails)
->filter(function ($email) {
return $email !== null; //ここでnull値を削除
})->all();
$this->merge([
'emails' => $emails,
]);
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'emails' => 'required|array', //入力を必須とする
'emails.*' => 'nullable|email|distinct',
];
}
public function messages()
{
return [
'emails.required' => '必ず1つの入力が必要です',
'emails.*.email' => '不正なメールです',
'emails.*.distinct' => '重複の入力があります'
];
}
}
最低1つの入力を条件とするために、'emails' => 'required|array', もrules()も追加しています。
さて、先の投稿でバリデートされたデータは、今度は以下のようにnullの値はなくなりました。
そして、何も入力がなく投稿された場合は以下のようなエラーとなります。
ちなみに、最低2つの入力を条件としたいときは、ルールを、'emails' => 'required|array|min:2', とすればよいです。






