複数行の入力フォームで、縦持ちの配列に対して複数の値を参照しながらバリデーションをしたいと思ったことはありませんか?
例えば、
- 縦持ちの配列に対するバリデーション方法が分からない
- 同じ行の情報(数量 × 単価 など)を組み合わせてチェックしたい
- laravel標準のバリデーションだけでは実装できない
- wijmo flexgridのデータをどう扱えばいいか分からない
今回は、縦持ち配列のデータに対して複数の値を参照しながら判定する
laravelのカスタムバリデーションを実際のサンプルコードを使って紹介します。
動的に行が増えるフォームや、明細入力のある画面などのケースです。
実際に私自身も、wijmoのflexgridに対してフォームの値にし、縦持ち配列のデータを扱う必要があり、
今回紹介する方法でカスタムバリデーションを実装しました。
同じような構成を扱っている方は、ぜひ参考にしてみてください。
- 縦持ち配列に対するバリデーションができるようになる
- 標準バリデーションでは対応できないケースの考え方が身につく
- 動的に行が増えるフォームでもそのまま使える実装が分かる
- wijmoのflexgridを使ったテーブルでも応用できる
実装
想定データ
まず、今回想定しているデータの形を先に見ておきます。
'grid_data' => [
0 => [
'item_name' => 'ノートパソコン',
'quantity' => 5,
'price' => 120000,
],
1 => [
'item_name' => 'マウス',
'quantity' => 2,
'price' => 1500,
],
]
フォームをPOSTすると、上記のように明細ごとに情報がまとまった「縦持ちの配列」が来ることを想定しています。
今回はこのデータに対して同じ行の「数量」と「単価」を参照しながらバリデーションを行う実装を紹介していきます。
補足
wijmoの場合、flexgridはHTMLフォームのinput要素ではないため、そのままではサーバーに配列として送信されません。
そのため、以下のようにgridのデータをJSONに変換し、input hiddenを使って配列として送信する必要があります。
let formElement = document.getElementById('form');
let flexGrid = wijmo.Control.getControl('#flexGrid');//frexgridのid
let source = flexGrid.collectionView.sourceCollection;
let input = document.createElement('input');
input.type = 'hidden';
input.name = 'grid_data';
input.value = JSON.stringify(source);
formElement.appendChild(input);
formElement.method = 'POST';
formElement.action = route;//POST先のルート
formElement.submit();実装する流れ
- POST先のコントローラのメソッドにカスタムバリデーションを定義する
- カスタムバリデーション内で複数の値を見て判定をするロジックを作成する
- エラーメッセージを定義する
- 項目に作成したバリデーションを指定する
カスタムバリデーションを定義
カスタムバリデーションの名前は「total_check」とします。
定義外の値を参照したい場合は、useを使って変数を渡します。
今回は数量が0より大きく、数量×単価が500,000を超えた場合にエラーとします。
public function postBlog()
{
//金額条件
$maxPrice = 500000;
//数量が0より大きい場合
Validator::extend('total_check', function ($attribute, $value, $parameters, $validator) use ($maxPrice) {
//getData()の中からgrid_dataを取得
$data = $validator->getData()['grid_data'];
list($dust1, $index, $dust2) = explode('.', $attribute);
$meisai = $data[$index];
//数量が0より大きいかつ、金額がmaxPriceより多い場合にエラーとする
$total = $meisai['quantity'] * $meisai['price'];
if ($meisai['quantity'] > 0 && $total > $maxPrice) {
return false;
}
return true;
});
//エラーメッセージを定義
$messages = [
'meisai.*.quantity.total_check' => '金額の合計が上限を超えています。',
];
}バリデーションの適用
バリデーションロジックを追加し、数量に対して作成したバリデーションを適用させます。
public function postBlog()
{
//金額条件
$maxPrice = 500000;
//数量が0より大きい場合
Validator::extend('total_check', function ($attribute, $value, $parameters, $validator) use ($maxPrice) {
$data = $validator->getData()['meisai'];
list($dust1, $index, $dust2) = explode('.', $attribute);
$meisai = $data[$index];
//数量が0より大きいかつ、金額がmaxPriceより多い場合にエラーとする
$total = $meisai['quantity'] * $meisai['price'];
if ($meisai['quantity'] > 0 && $total > $maxPrice) {
return false;
}
return true;
});
$messages = [
'meisai.*.quantity.total_check' => '金額の合計が上限を超えています。',
];
//↓追加↓
// エラーチェック
$validator = Validator::make(request()->all(), [
'name' => ['required'],
'age' => ['required', 'integer'],
'meisai.*.quantity' => ['required', 'numeric', 'between:0,100', 'total_check'],
'meisai.*.price' => ['required', 'numeric', 'between:0,1000000'],
'meisai.*.comment' => ['nullable', 'string', 'max:100'],
],
$messages,
);
if ($validator->fails()) {
// エラーの中身を取得
$errors = $validator->errors();
dd($errors->toArray());
}
//↑追加↑
}エラーの場合は、エラーの内容を「dd()」で画面に出力し、処理を止めます。
確認のために、数量を「5」、単価を「120000」にしてPOSTしてみます。


ちゃんと定義したエラーメッセージが出力されました。
まとめ
縦持ち配列のデータに対して複数の値を参照してチェックするlaravelのカスタムバリデーション方法を紹介しました。
標準のバリデーションでは対応しづらい複数の項目チェックも、「Validator::extend」を使って柔軟に実装できます。
また、FlexGridや動的な明細フォームなど、行数が増減するフォームでも今回の内容を参考に対応することができると思います。
横持の配列に対してのバリデーション方法は以下の記事で紹介しておりますので、こちらも併せて読んでみてください。
【laravel】配列に対してバリデーションをする方法
