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
メソッドでカスタムルールを登録- 第一引数がルール名、第二引数にバリデーションの処理、第三引数がエラーメッセージ
- バリデーション処理の戻り値は
true
orfalse
- エラーメッセージのプレースホルダーは
: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
メソッドでカスタムルールを登録- 第一引数がルール名、第二引数にバリデーションの処理、第三引数がエラーメッセージ
- バリデーション処理の戻り値は
true
orfalse
- エラーメッセージのプレースホルダーは
{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を組み合わせると自在にバリデーションが書ける! - アクトインディ開発者ブログ