JavaScript 側のバリデーションを validatorjs 、 PHP 側のバリデーションを vlucas/valitron で作成していたのですが、チェックボックスのバリデーションについてカスタムルールを作る必要が出てきたのでメモしておきます。
前提
フォームの例を以下に示します。
<form action="cockadoodledoo" method="post">
<label for="divinity" class="col-md-3 col-form-label text-right">
ご祭神
</label>
<div class="form-check form-check-inline">
<label class="form-check-label">
<input type="checkbox" class="form-check-input" id="divinity0" name="divinity[]" value="天村雲神・天水雲神・天御雲神">天村雲神・天水雲神・天御雲神
</label>
<label class="form-check-label">
<input type="checkbox" class="form-check-input" id="divinity1" name="divinity[]" value="天水分神・国水分神">天水分神・国水分神
</label>
<label class="form-check-label">
<input type="checkbox" class="form-check-input" id="divinity2" name="divinity[]" value="水波女神・水速女神">水波女神・水速女神
</label>
<label class="form-check-label">
<input type="checkbox" class="form-check-input" id="divinity3" name="divinity[]" value="綿津見神">綿津見神
</label>
<label class="form-check-label">
<input type="checkbox" class="form-check-input" id="divinity4" name="divinity[]" value="大己貴神">大己貴神
</label>
<label class="form-check-label">
<input type="checkbox" class="form-check-input" id="divinity5" name="divinity[]" value="阿須波神・波比岐神">阿須波神・波比岐神
</label>
<label class="form-check-label">
<input type="checkbox" class="form-check-input" id="divinity6" name="divinity[]" value="高皇産霊神">高皇産霊神
</label>
<label class="form-check-label">
<input type="checkbox" class="form-check-input" id="divinity7" name="divinity[]" value="伊邪那岐命・伊邪那美命">伊邪那岐命・伊邪那美命
</label>
<label class="form-check-label">
<input type="checkbox" class="form-check-input" id="divinity8" name="divinity[]" value="天御中主神">天御中主神
</label>
</div>
</form>
普通のチェックボックスですね。
ただし、今回はこれをそのまま処理するわけではありません。
確認画面をモーダルで済ませたかったので、 JavaScript で一度チェックの入った値を取得し、カンマ区切りの文字列として保持、それを hidden パラメータにセットする、ということをしています。
つまり、実際は以下のような形でセットされます。
<form action="cockadoodledoo" method="post"><label for="divinity" class="col-md-3 col-form-label text-right">ご祭神</label><div class="form-check form-check-inline"><label class="form-check-label"><input type="checkbox" class="form-check-input" id="divinity0" name="divinity[]" value="天村雲神・天水雲神・天御雲神">天村雲神・天水雲神・天御雲神</label><label class="form-check-label"><input type="checkbox" class="form-check-input" id="divinity1" name="divinity[]" value="天水分神・国水分神">天水分神・国水分神</label><label class="form-check-label"><input type="checkbox" class="form-check-input" id="divinity2" name="divinity[]" value="水波女神・水速女神">水波女神・水速女神</label><label class="form-check-label"><input type="checkbox" class="form-check-input" id="divinity3" name="divinity[]" value="綿津見神">綿津見神</label><label class="form-check-label"><input type="checkbox" class="form-check-input" id="divinity4" name="divinity[]" value="大己貴神">大己貴神</label><label class="form-check-label"><input type="checkbox" class="form-check-input" id="divinity5" name="divinity[]" value="阿須波神・波比岐神">阿須波神・波比岐神</label><label class="form-check-label"><input type="checkbox" class="form-check-input" id="divinity6" name="divinity[]" value="高皇産霊神">高皇産霊神</label><label class="form-check-label"><input type="checkbox" class="form-check-input" id="divinity7" name="divinity[]" value="伊邪那岐命・伊邪那美命">伊邪那岐命・伊邪那美命</label><label class="form-check-label"><input type="checkbox" class="form-check-input" id="divinity8" name="divinity[]" value="天御中主神">天御中主神</label></div></form>
この値をバリデーションしたい、と。
validatorjs
まずは JavaScript 側。 script タグで本体読み込み済みとします。
//custom validatorjs / checkbox
Validator.register('checkbox', function (value, requirement, attribute) {
const valArray = value.split(',');
for (const val of valArray) {
if (requirement.indexOf(val) === -1) {
return false;
}
}
return true;
}, ':attribute は無効です。');
//generate instance
const validatorjs = new Validator(arrayData, rules);
registerメソッドでカスタムルールを登録- 第一引数がルール名、第二引数にバリデーションの処理、第三引数がエラーメッセージ
- バリデーション処理の戻り値は
trueorfalse - エラーメッセージのプレースホルダーは
:attribute
となっています。
今回は必須は標準の required に任せて、最初にカンマ区切りの文字列を配列に戻した後に、「各値( val )が想定される値の配列( requirement )に含まれるかどうか」をチェックしています。
Valitron
続いて PHP 側。
//custom valitron / checkbox
\Valitron\Validator::addRule('checkbox', function ($field, $value, array $params, array $fields) {
$valArray = explode(',', $value);
for ($i = 0; $i < count($valArray); $i++) {
if (!in_array($valArray[$i], $params[0], true)) {
return false;
}
}
return true;
}, '{field}が無効な値です。');
//generate instance
$v = new \Valitron\Validator($post);
addRuleメソッドでカスタムルールを登録- 第一引数がルール名、第二引数にバリデーションの処理、第三引数がエラーメッセージ
- バリデーション処理の戻り値は
trueorfalse - エラーメッセージのプレースホルダーは
{field} - バリデーション処理の引数は以下の通り
$field: フィールドのキー名(イメージとしてはname属性に指定された$_POSTのキー)$value: 入力値$params: 要件。想定される値の配列
全体的な使い方は validatorjs と似ています。
やや引っかかったのは要件が配列に入っているので、アクセスの際は $params ではなく $params[0] を使うこと。
JavaScript 側と同様、必須要件は required に任せて「各値( $valArray[$i] )が想定される値の配列( $params[0] )に含まれるかどうか」のチェックに専念しています。
ちなみに、 Valitron は subset というルールが標準で存在するためこれが使えそうだと思ったのですが、思うように動かなかったのでカスタムルールを作成することにしました。
備考
今回の JavaScript での値の取得(input type="checkbox" から 文字列へ)は以下のような処理で実装しました( jQuery 使用)。
let arrayData = [];
let strArrayCheckbox = '';
$(`input[name="divinity[]"]:checked`).each(function (index) {
strArrayCheckbox += $(this).val();
if (index < $(`input[name="divinity[]"]:checked`).length - 1) {
strArrayCheckbox += ',';
}
});
arrayData['divinity'] = strArrayCheckbox;
一応メモ。
参考
validatorjs
- validatorjs - npm
- validatorjsのカスタムルールを書くときの注意点 - Qiita
- Vue+Vuexにvalidatorjsを組み合わせると自在にバリデーションが書ける! - アクトインディ開発者ブログ