PHPackages                             ryunosuke/chmonos - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Validation &amp; Sanitization](/categories/validation)
4. /
5. ryunosuke/chmonos

ActiveLibrary[Validation &amp; Sanitization](/categories/validation)

ryunosuke/chmonos
=================

Compatible php/js validator library

v2.2.14(3mo ago)0598MITPHPPHP &gt;=8.0

Since Nov 24Pushed 3w ago1 watchersCompare

[ Source](https://github.com/arima-ryunosuke/php-validator)[ Packagist](https://packagist.org/packages/ryunosuke/chmonos)[ RSS](/packages/ryunosuke-chmonos/feed)WikiDiscussions master Synced 1w ago

READMEChangelogDependencies (6)Versions (81)Used By (0)

php/js Validation Library
=========================

[](#phpjs-validation-library)

Description
-----------

[](#description)

- 宣言的な記述で php/js の両方で同じルールを適用してバリデーションを行います
- 単純な検証ではなく、「あの値があれだったらこの値はこれ」のような条件付けも出来ます
- input のレンダリングと統合しているため、値戻しやタグの記述は原則として不要です

Install
-------

[](#install)

```
{
    "require": {
        "ryunosuke/chmonos": "dev-master"
    }
}
```

Demo
----

[](#demo)

```
cd /path/to/chmonoce
composer example
# access to "http://hostname:3000"
```

Usage
-----

[](#usage)

### 基本

[](#基本)

js チェックを行うのでいくつかの静的ファイルが必要です。 `script` ディレクトリ以下が該当します。

- `validator.js`: js チェックのコア js ファイルです
- `validator-error.js`: エラー表示用の js ファイルです
- `validator-error.css`: エラー表示用の css ファイルです

なお、 js チェックのエラー表示は完全に分離しているので比較的容易にすげ替えることが可能です。 上記の下2つのファイルがエラー表示を担当します。これらのファイルを変更することでエラー表示をカスタムできます。

php 側では下記に続くようなルールを配列で宣言的に記述して Form インスタンスを作成し、レンダリングすれば `` タグが得られます。 その form で submit して validate メソッドで入力値の検証を行います（js バリデーションは原則として画面内で自動的に行われます）。

Form にはいくつかのオプションがあります。

```
// Form インスタンスを作成
$form = new Form([/* ルールについては後述 */], [
    'nonce'      => '',           // 生成される script タグの nonce 属性を指定します（CSP 用です。不要なら指定不要です）
    'inputClass' => Input::class, // UI 要素の検証やレンダリングに使用する Input クラス名を指定します。基本的には指定不要です
    'fileClass'  => null          // アップロードファイルのクラス名を指定します。指定しないと tmp_name が文字列として渡ってきます
    'vuejs'      => 'unique-id',  // レンダリングが vuejs に適した形になります
]);

// POST でバリデーション
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $form->validateOrThrow($_POST);
}

// レンダリング
$form->form([/* form の属性*/]); // form 開きタグ
$form->form();                   // form 閉じタグ（引数無しで閉じる）
```

上記が基本的な使い方となります。 example ではほぼすべての機能を使用しているので参考にしてください。

#### ルールの記述

[](#ルールの記述)

Form のルールには下記のような連想配列を渡します。 大量にありますが、ほとんどはデフォルト値でそれなりに動くので、指定するのはごく一部です（究極的には空配列でも動きます）。

配列ではなく null を与えるとその要素はスルーされ、無かったことになります。

```
$form = new Form([
    'element_name1' => [
        'title'                 => '',         // 画面に表示される際の論理名を指定します
        'label'                 => '',         // label 化された場合の文字列を指定します（省略時は title）
        'normalize'             => [],         // 入力値のプレフィルタです（後述）
        'condition'             => [],         // 入力条件を配列で指定します（後述）
        'options'               => [],         // checkbox や radio などの選択肢を配列で指定します。キーが値、値が表示文字列です
        'presents'              => [],         // 必須 options を指定します（後述）
        'present-option-prefix' => "\x16",     // 必須 options を表すプレフィックスを指定します（後述）
        'missings'              => [],         // 無効 options を指定します（後述）
        'missing-option-prefix' => "\x18",     // 無効 options を表すプレフィックスを指定します（後述）
        'datalist'              => [],         // datalist を生成します。現状では「自動 Condition が行われない options」という仕様です
        'event'                 => ['change'], // js チェックが走るイベント名を指定します（後述）
        'propagate'             => [],         // js チェックのイベントの伝播先を指定します（後述）
        'message'               => [],         // エラーメッセージを指定します（後述）
        'phantom'               => [],         // 疑似データソースを指定します（後述）
        'attribute'             => [],         // その他のカスタムデータです。html レンダリングされる際のタグ属性にもなります
        'inputs'                => [],         // ネスト構造を再帰的に記述します（後述）
        'checkmode'             => [           // サーバー・クライアントサイドのどちらで検証を行うか指定します（非推奨。将来的に削除されます）
            'server' => true,        // server を true にするとサーバーサイドで検証が行われます
            'client' => true,        // client を true にするとクライアントサイドで検証が行われます
        ],
        'wrapper'               => null,       // input 要素をラップする span class を指定します。未指定だとラップしません
        'grouper'               => null,       // input 要素郡（同じ名前の radio/checkbox）をラップする span class を指定します。未指定だとラップしません
        'option-label'          => [null],     // option のラベルを出す属性を指定します（null は textnode を表す）。実質的に null, 'label', 'title' の3択です（あるいは data-* 属性）
        'invisible'             => false,      // 不可視状態で検証を行うかを指定します
        'ignore'                => false,      // 検証や依存関係の値としては全て有効ですが最終的な結果から除くかを指定します（後述）
        'trimming'              => true,       // 値のトリミングを行うかを指定します。'left','right' という文字列を指定すると左右どちらかに限定できます
        'needless'              => [],         // 必須ではない場合の属性を指定します（後述）
        'autocond'              => true,       // 一部の入力条件を自動設定するかを指定します（後述）
        'delimiter'             => null,       // 配列⇔文字列の区切り文字を指定します（後述）
        'multiple'              => null,       // 複数入力か否かを指定します（後述）
        'dependent'             => true,       // 自動伝播設定を行うかを指定します（後述）
        'pseudo'                => true,       // ダミー hidden を生成するかを指定します（後述）
        'nullable'              => false,      // 値が null の場合でも default 値を使用するか指定します
        // 'default'               => null,       // 値が飛んでこなかった時のデフォルト値を指定します（後述）
        // 'fixture'               => null,       // Form/Context の getFixture が呼ばれた時に固定値として使用されます（後述）
    ],
    'element_name2' => [/* 構造は同じ */],
    // ・・・
]);
```

一部、難解なオプションがあるので掘り下げていきます。

##### normalize

[](#normalize)

バリデーションに先立って、値を引数にコールバックされるクロージャです。

php のみの設定です。js 側では使用されません。 基本的にはサーバーサイドでしか検知できない値のフィルタや変換を行いますが、そこまで用途はないでしょう。

##### condition

[](#condition)

入力条件を指定します。

指定は原則として `条件クラス => [パラメータ]` です。

```
$rule = [
    'condition' => [
        'Requires' => [],
        'Decimal'  => [3, 2],
        'Range'    => ['min' => -200, 'max' => 200],
    ],
];
```

とすると「入力必須」で「小数 xxx.yy」で「範囲 -200 ～ 200」を表します。

指定の仕方はいくつかあり、下記は全て正しい指定です。

```
$rule = [
    'condition' => [
        'Range'      => [-200, 200],          // 上述の条件クラス => [パラメータ]
        Range::class => [-200, 200],          // FQSEN 指定
        '-200~+200'  => new Range(-200, 200), // インスタンス直接指定
    ],
];
```

基本的には `条件クラス => [パラメータ]` で良いです。後からのハンドリングもしやすいです。 ただ、 「複数の同じ Condition を引数違いで使いたい（`Compare` など）」場合に対応できないため、そういう場合は他の指定方法を選ぶ必要があります。

各 Condition のパラメータはソースコードや DocComment を参照してください。 コンストラクタの引数がそのまま使用されます。

`Child` サフィックスがついている Condition は type=array 専用です。 このサフィックスがついている Condition は原則的に自身の行・列の列に対して串刺し的な条件を設定します。 例えば「行要素に特定の値を含む」「値の重複チェック」等です。

値が null でキーが数値だとスルーされ、無かったことになります。

##### message

[](#message)

エラーメッセージをカスタムします。

エラーメッセージは「form =&gt; input =&gt; condition =&gt; type =&gt; message」という階層構造を持ちます（フォームがインプットを持ち、インプットがコンディションを持ち、コンディションがエラー配列を持ちます）。 この構造の `type => message` 部分を指定します。

```
$rule = [
    'message' => [
        'RequireInvalidText'       => '入力必須です',
        Requires::INVALID_MULTIPLE => '選択必須です',
    ],
];
```

このようにするとエラーメッセージをカスタムできます。指定しないとデフォルトメッセージが使用されます（一応、それらしいメッセージにはなっています）。 上は直指定、下は定数指定ですが、変更に備えて定数指定を推奨します。

ただし、この指定だと「複数の同じ Condition を引数違いで使いたい（`Compare` など）」場合に全て同じメッセージになってしまいます。 個別でメッセージ変更したい場合はネストした配列を渡すことで `condition => type => message` の階層から指定することが出来ます。

```
$rule = [
    'message' => [
        'condition1' => [
            'RequireInvalidText'       => '入力必須です1',
            Requires::INVALID_MULTIPLE => '選択必須です1',
        ],
        'condition2' => [
            'RequireInvalidText'       => '入力必須です2',
            Requires::INVALID_MULTIPLE => '選択必須です2',
        ],
    ],
];
```

condition1 や condition2 は `condition` 配列のキーと同じものを指定します。

また、メッセージ中に `${_name}` という文字列を埋め込むとクラスの同名フィールドで置換されます。 例えば組み込みの `Decimal` Condition は `'整数部分を${_int}桁、小数部分を${_dec}桁以下で入力してください'` というものがあります。 この中の `${_int}` `${_dec}` はパラメータで指定した値に置き換えられます。

この記法は js のテンプレートリテラルを模しているため、`${implode(",", _types)}` のような式の埋め込みも可能です。 いくつかの Condition では使用しているため参考にしてください。 ただし、式として利用できる関数は内部で定義されているものだけです。 共通メッセージとして設定したものはビルド時に追加されますが、個別設定した場合は使用できません。 ので「共通で定義した上で個別で上書く」という処理が必要です。

なお、このキーでエラーメッセージを変更してもその要素のみに影響します。 js の容量削減のため、構造的には「共通メッセージがあり、変更した場合のみ個別メッセージが使われる」という動作になっています。 全体共通メッセージを変えたい場合は大本のクラスを書き換えるか `AbstractCondition::setMessages` を使用します。

エラーメッセージは一切 html エスケープが行われないので注意してください。 エスケープはエラー表示プラグインの仕事と割り切って、本体側ではタッチしない設計です。

##### options

[](#options)

checkbox, radio, select などの選択肢を指定します。 1階層のネストは optgroup として扱われます。

`options` が指定されると autocond 機能により InArray 条件が自動で付与されます。 `presents` が指定されると autocond 機能により ArrayInclusion 条件が自動で付与されます。 `missings` が指定されると autocond 機能により NotInArray 条件が自動で付与されます。その際、ラベル文字列はこちらの指定で上書きされます。

`present-option-prefix` を指定するとそのプレフィックスが付いた要素は presents に入っているように振る舞います。 要素のプレフィックスは除去されます。 `missing-option-prefix` を指定するとそのプレフィックスが付いた要素は missings に入っているように振る舞います。 要素のプレフィックスは除去されます。

キーは値になります（1階層のネストは optgroup のタイトル）。 値はラベルになりますが、ラベルは stdClass が許容されます。 stdClass の場合、 `label`, `present`, `missing` というプロパティが特別扱いされ、`label` がラベルに、`present/missing` が上記で言う `present/missing-option-prefix` が指定された値にあたります。 その他の属性は html の属性値になります。 つまり、下記のコードは（ほぼ）等価です。

```
$rule = [
    'options'    => [
        10 => '電話',
        20 => 'メール',
        30 => "FAX",
    ],
    'presents'   => [
        20 => "メール", // これは presents 機能により ArrayInclusion 条件で必須の要素とみなされる
    ],
    'missings'   => [
        30 => "FAX（無効状態）", // これは missings 機能により NotInArray 条件で不正な値とみなされる
    ],
];
$rule = [
    'options'    => [
        10 => '電話',
        20 => "\x16メール", // これは present-option-prefix 機能により ArrayInclusion 条件で必須の要素とみなされる
        30 => "\x18FAX",    // これは missing-option-prefix 機能により NotInArray 条件で不正な値とみなされる
    ],
];
$rule = [
    'options'    => [
        10 => (object) ['label' => '電話', 'data-attr' => '10'],
        20 => (object) ['label' => 'メール', 'data-attr' => '20', 'present' => true], // これは autocond 機能により ArrayInclusion 条件で必須の要素とみなされる
        30 => (object) ['label' => 'FAX', 'data-attr' => '30', 'missing' => true],    // これは autocond 機能により NotInArray 条件で不正な値とみなされる
    ],
];
```

違いは option に `data-attr` という属性値が生やせることです。

なんでこんな仕様が必要かと言うと、missing は「現在選択肢が何らかの理由により無くなった」という仕様に耐えるためです。 例えばマスタから消えた、DB から論理削除された、等です（上記で言うと 30:FAX という選択肢が消えた状態）。

html の select は候補が不正な場合（value が 30:FAX なのに 30:FAX という option がない状態）に「一番上を自動選択する」という仕様があるので、何も考えずに実装すると画面を開いてただ保存しただけで値が 10:電話 に勝手に変わってしまう、という事象が発生します。 radio/checkbox はそういうことは起こりませんが、多くの場合は必須エラーとなりますし、現在の選択肢が何だったのか？ という情報が失われ、利便性が落ちます。 そのような時、missings で無効候補を与えたり、prefix を付与することで現在の選択肢を保ちつつ NoInArray でエラーにすることができます。

選択肢が共通でマスタ的な場合は `missing-option-prefix` がいいでしょう。定義場所で "\\x18" を付与するだけで全体として無効化できます。 DB 等から動的に構築する場合は `missings` がいいでしょう。options を取得するついでに missings も取得すれば無効化できます。

一方、present は「何らかの理由で削除不可」という仕様に耐えるためです。 例えばマスタ的なもので「子テーブルで使われているため削除不可」等です（上記で言うと 20:メール という選択肢が使用状態）。

通常であれば外部キーなどのチェックで事足りますが、こういった項目は往々にして checkbox\[\] や select\[multiple\] で構成されるため、画面内でのエラー可否が非常に煩雑になります。 そのような時、presents を与えたり、外部キーを見て prefix を付与することで削除禁止にすることができます。

##### event

[](#event)

js バリデーションが走るイベント名を指定します。基本的には change か input の2択でしょう。 特殊な仕様として jQuery の名前空間のように `change.modifier` とドット区切りで修飾子をつけるとそのイベントに対して特殊な属性をつけることができます。

**noerror**

`event.noerror` とすると「エラーになるときには発火しない」という動作になります。 逆に言うと「エラーが解除されるときのみ発火する」となります。

例えば `['change', 'input.noerror']` とすると「変更時にはエラーになるが入力時にはエラーにならない」という動作になります。 これは入力途中にエラーになると画面がうるさい or 邪魔になる、というよくある動作を回避するためのものです。

メールアドレスを入力しようとして `hogera@` までタイプしてエラーになるのは確かにうるさいです。つまり input をつけることは出来ません。 一方、 `hogera@example..com` の入力ミスを修正するときは `.` を消した時点でエラーが消えるほうが親切でしょう。つまり input をつける必要があります。 そんなとき `['change', 'input.noerror']` とすると望ましい動作を実現することが出来ます。

**norequire**

`event.norequire` とすると「依存関係（propagate, dependent も参照）起因での検証のときに必須エラーを出さない」という動作になります。

例えば `希望連絡方法： ○電話 ○FAX ／ 電話番号[　　　　　　], FAX[　　　　　　]` という UI で○電話にチェックを入れた瞬間に電話番号が必須エラーとなるのは時期尚早です。ユーザはまだ入力しておらず電話番号という項目があることすら認識していないためです。 かと言って propagate, dependent で依存関係を解除すると普通の検証イベントも伝播しなくなります。 この修飾子で抑制するのはあくまで必須エラー（Requires）だけです。

かなりニッチな用途でかつ破壊的変更の予定があります。具体的には「DOM 順、座標が後方なら検証しない」という動作への変更予定があります。作者が必要に迫られて新設された修飾子であり、一般向けではないので原則として使用は非推奨です。

上記が実装されました。必須エラー以外も伝播されなくなりますが、この指定は `propagate:preceding` の下位互換です。 propagate も参照してください。

##### propagate

[](#propagate)

要素に検証が走ったときに合わせて検証する要素を指定します。

例えば `☑ 必須： [　　　　　　]` のような UI でチェックボックスにチェックを入れたときにテキストフィールドにイベントが伝播するように出来ます。 ただし、ルールからある程度推測して自動設定されるため、明示的に指定する状況はあまりありません。

これに関しては後述の `dependent` を参照してください。

指定は連想配列で `['伝播要素名' => 'モード']` と指定します。 連想配列ではない普通の連番配列も受け入れますが後方互換性のためです（連番配列だとモードが null だとみなされます）。

モードは現在のところ null/preceding/following だけです。

- null は特殊なことをせず単純に伝播されます
- preceding は DOM 順で対象が前の時のみ伝播します
- following は DOM 順で対象が後の時のみ伝播します

following はほぼ使いません。 preceding は UI 的に先の要素に伝播したくない場合に使えます。

例えば `希望連絡方法： ○電話 ○FAX ／ 電話番号[　　　　　　], FAX[　　　　　　]` という UI で○電話にチェックを入れた瞬間に電話番号が必須エラーとなるのは時期尚早です。ユーザはまだ入力しておらず電話番号という項目があることすら認識していないためです。

##### phantom

[](#phantom)

他のフィールドの値を結合して自身の値とします。

例えば \[年\] \[月\] \[日\] の3フィールドがあるとして、自身の値は \[年月日\] として日付バリデーションをしたい場合です。

```
$rule = [
    'phantom' => ['%04d/%02d/%02d', 'year', 'month', 'day'],
];
```

このようにすると年月日として構築されます。要するに `vsprintf($phantom[0], ...array_slice($phantom, 1))` された値が自身の値になるということです。

##### inputs

[](#inputs)

ネスト要素を記述します。

```
$rule = [
    'inputs' => [
        'child_element_name1' => [/* 構造は同じ */],
        'child_element_name2' => [/* 構造は同じ */],
        // ・・・
    ],
];
```

このようにすると input 要素があたかも階層構造を持つような html が生成されます。 「画面内でボタンを押すと要素セットが追加される」ような状況で使用します。 ただし、かなり複雑になる上 context/template/vuefor の使用がほぼ必須になります。

なお、ネストできるのは2階層までです。それ以上ネストした場合の動作は未定義です。

##### ignore

[](#ignore)

最終的な結果から取り除くかを指定します。

Requires や Compare, phantrom などで「最終的な結果としては不要だが、ルールとしては必要」という要素が出てくることがあります。 例えば

- Compare で現在日時と比較したいので `now` 要素が必要
- Requires で内部的に `ID` を持っているかが必要
- Ajax で依存値を投げたい

のような状況です。 これらは依存関係の解決や、他の要素のためだけに存在しているもので、最終的な検証値としては不要なことが多いです。 そんなとき、 ignore: true を指定すれば最終的に validate や validateOrThrow で得られる値から自動的にフィルタされるようになります。

また、この属性には省略属性があり、`@element_name` のように要素名に `@` を付与すれば自動で ignore: true とみなされるようになります。

##### needless

[](#needless)

必須ではないときの html input 属性を指定します。

「必須ではない」とは「条件付き Requires が指定されているが、条件に一致していないとき」を意味します。 将来的に Requires と対を為す Condition が追加されるかもしれませんが、その意味合いは変わりません。

※ 「必須」なら必須だが「必須ではない」は入力不可を意味しない ※ 「入力不可」なら入力不可だが「入力不可でない」は必須を意味しない ※ つまり2値論理ではなく「必須」「任意」「入力不可」という3値論理なので Requires だけでは足りなくなっている

「必須じゃないときは入力できないようにする」「必須じゃないときは表示から消す」という要件が稀によくあり、そのようなときに js で頑張るのもつらいので組み込みとしています。

指定は任意の属性を指定できるようにしてありますが、実質的には下記の3属性のいずれかでしょう。 あるいは css での香りづけとして data- 属性を渡すことがある程度です。

- readonly: 入力できないし見えるし選択もできるが、対応していない input がある
- disabled: 入力できないし見えるし選択もできるが、値が飛ばない（それが望ましい場合もある）
- inert: 入力できないし見えるが選択ができない

どれも特徴があるので用途に合わせて選ぶべきです。 連想配列を想定していますが、上記のような論理属性であれば単一文字列・連番配列での指定も可能です。

なお、css の `:has` が十分実用的なので、

```
.wrapper:has(input[inert]) {
}
```

等のようにすればブロック単位で消すとか見えなくするとかの対応は js なしで可能です。 なので needless を指定しても属性付与に留め、DOM 構造には一切触らない実装になっています。

##### autocond

[](#autocond)

ルールの記述から condition が自動で設定できるようであれば設定します。 例えば

- options があるときに InArray condition
- maxlength が導出できるときは StringLength condition

が自動設定されます。同種の condition が設定されているときは上書きしません。

この処理は Input クラスの `_setAutoXXX` を検出して自動で呼ばれるようになっています。 言い換えれば `_setAutoHoge` というメソッドを生やすことで condition の自動設定を拡張できます。

どの自動設定を行うかは配列で指定できます。例のように true/false で指定した場合は全設定/全未設定を意味します。

```
$rule = [
    'autocond' => [
        'InArray'      => true,
        'StringLength' => false,
    ],
];
```

これは前述の「options があるときに InArray condition」だけを設定することを意味します。 また、 Input クラスに `_setAutoHoge` メソッドが存在するときに `['Hoge' => false]` を指定すると Hoge も除外されるようになります。 指定されなかった condition は true 扱いになります。

true の代わりにクロージャを渡すと自動生成された Condition インスタンスを引数としてコールバックされます。 これは validationLevel や message を設定したい際に有用です。

##### dependent

[](#dependent)

依存項目を指定します。

`propagate` と対になる設定です。 propagate は「自身**の**イベントを伝播する要素（自身 -&gt; 相手）」を指定しますが、この `dependent` は「自身**へ**イベントを伝播する要素（相手 -&gt; 自身）」を指定します。 あまり違いはありませんが、親から子、子から親の場合で指定の仕方が微妙に異なります。 また、 true にするとルールに基づいて自動で相手の `propagate` にマージされます。

例えば `☑ 必須： [　　　　　　]` のような UI でチェックボックスにチェックを入れたときにテキストフィールドにイベントが伝播するように出来ます。 本来なら `☑ 必須` に対して `propagate` を設定するのが筋ですが、 ` [　　　　　　]` に `Requires(checked)` のような条件が設定されていれば「チェックが入っていれば必須」という関連を自動で導き出すことが出来ます。 true はそれを設定するかしないかのフラグです。

true 単値でも `['elemname', true]` のような配列でも指定できます。これは「elemname と自動設定」を意味します。

##### delimiter

[](#delimiter)

配列⇔文字列の区切り文字を指定します。

区切り文字を指定すると自動で multiple も true になります。 そして値として文字列が飛んできた場合に区切り文字で自動で配列化されます。

主な用途は「URL の短縮」というニッチな機能です。 往々にして `[]` での配列のマルチ選択は URL が長くなりがちで、場合によってはブラウザの制限を超えることがあります（2000文字くらい）。

例えば multiple select などで `something_id[]` という名前で 100 件選択するとそれだけで `something_id[]=10001&something_id[]=10002&...`(約40文字) となり、全部で約 2000 文字になってしまいます（url エンコードや `&` 記号は除外）。 そのような時、このオプションで例えば `,` を指定すると `something_id=10001,10002,...`(13+6\*100=613) となり、大幅に URL を短縮することができます。

変換は暗黙的に行われます。原則として利用側で意識する必要はありません。

##### multiple

[](#multiple)

値の複数値を許可します。 具体的には

- select: multiple 属性が付きます
- file: multiple 属性が付きます
- 上記も含めて radio 以外の全てのタイプの名前が `name[]` になります

デフォルトは `null` で、ある程度自動設定されます（デフォルト値が配列の場合など）。

##### pseudo

[](#pseudo)

input のレンダリング時に直前に hidden を挿入します。

html における checkbox は未チェックだと値が飛ばないため、常にルールの default 値が使われてしまいます。 このオプションを設定すると未チェック時でも空文字・空配列（multiple 時）が飛ぶようになります。

さらに空文字が飛んだ場合の初期値としてこのキーに指定した値が使われます。 true を指定すると配列の場合は空配列、そうでなければ空文字を指定したのと同等になります。

原則として checkbox 専用ですが、multiple な select にも同様のことが言えるので multiple select も対象です。 その他の要素では単に無視されます。

##### default

[](#default)

値が飛んでこなかった時のデフォルト値を指定します。

明示的に指定するとそれが使用されます。 指定しないとルールに基づいて自動で算出されます。 例えば inputs が指定されていれば `[]` だし、 options が指定されていればその最初の値です。

この自動処理は互換性を保たず変更されるため、可能なら明示的に指定するようにしてください。

デフォルトでは「値が飛んでこなかった時」であることに注意してください。 isset でも strlen でもなく、本当になかったときのみに適用されます。端的に言えば `array_key_exists` 判定です。 ただし、それだとチェックボックスについては少々都合が悪いため `pseudo` でダミー hidden が生成できます。

`nullable` を true にすると値が null の場合でも default 値が使われるようになります。端的に言えば `isset` 判定です。

pseudo と default の違いは下記となります。

- pseudo: checkbox/select で選択されなかったときの既定値
- default: setValues の初期値、飛んでこなかったときの初期値、template/context での初期値

##### fixture

[](#fixture)

Form/Context には `getFixture` というメソッドが生えており、「その Form/Context の検証をパスするであろう値」を自動生成できます。 ただあくまで自動生成であるため、そのままでは検証を通らないことも多いです。

この `fixture` を指定すると自動生成ではなく、その指定した値が明示的に使用されるようになります。 クロージャを渡すとコールされます。これは「fixture なんてテストでしか使わないのに値を生成したくない」という状況を満たすためです。

##### その他のルール

[](#その他のルール)

ルールは上記のような既定キー以外でフィルタされたりはしません。 適当なキーで適当に値を渡せば `$input->hoge` で参照可能です。

これは拡張性を考慮してのことですが、将来の verup でキーが被ると互換性が崩れるため、何らかのプレフィックスをつけるなどで対処してください。

#### レンダリング

[](#レンダリング)

作成した $form オブジェクトを用いて下記のようにレンダリングします。

```
// form 開きタグ
$form->form([/* form の属性*/]);
// label タグ
$form->label('element_name', [/* label の属性 */]);
// input タグ
$form->input('element_name', [/* input の属性 */]);
// form 閉じタグ（引数無しで閉じる）
$form->form();
```

このとき、 form の `data-validation-event` に `click` を与えるとバリデーションのタイミングが submit ボタンの click 時になります。 未指定時は form の submit 時です。 button click 時の方が何かと都合がいいため、`click` 指定を推奨します。

vuejs の機能を使うなら `/* form の属性*/` に `['vuejs' => 'unique-id']` を与える必要があります。 これで v-model や :data-vinput-id などが出力され、 vuejs でもそれなりに動くようになります。

属性は基本的に name=value の連想配列を与えるだけです。 特殊な処理として「値が false の場合はその属性はなくなる」というものがあります。 これは `readonly` などの論理属性を想定しています。

form タグの属性はある程度よしなに設定されます。 例えば file 要素があると post な multipart/form-data になったりします。 しかし、レンダリング時に明示的に指定しているときは必ずそれが優先されます。

input タグの属性はいくつか特殊な属性があります（カッコ内はデフォルト属性）。

- 共通
    - name: ルール定義に応じて自動設定されます。指定しても無視されます
    - id: 指定しなかった場合、自動で設定されます id &lt;=&gt; for 関連で使用されます
    - type: html における input type 属性です。textarea や select なども統一して使用できます。指定しなかった場合、ルールに応じて自動で推測します
    - class: 指定したとおりになりますが、 `validatable` は必ず付与されます
- type=select の場合
    - option\_attrs(\[\]): 各 option の属性連想配列を指定します
- type=checkbox の場合
    - multiple(false): ルール配列の multiple と同じ効果があり、name 属性に `[]` が付与されます
    - wrapper(null): ルール配列の wrapper と同じ効果があり、input タグが span でラップされます
    - grouper(null): ルール配列の grouper と同じ効果があり、同名 input タグが span でグルーピングされます
    - labeled("right"): 弟要素として label タグを生成します。"outer" とすると親要素として生成します
    - label\_attrs(\[\]): labeled が有効な場合の label 側の属性連想配列を指定します
    - format(null): 最終的な html を sprintf します。例えば `%s` として div で囲めます
    - separator(null): 複数要素の場合のセパレータを指定します。例えば `separator => ''` として選択肢を改行区切りにします
- type=radio の場合
    - multiple 以外は checkbox と同じです

label タグの属性は特筆すべきことはありません。 敢えて言うなら for, class は自動設定されます（指定した場合はそれが優先）。

ファイル用のドロップ UI が用意されており、 `.vfile-dropzone` という DOM を準備しておけばそこにファイルがドロップできるようになっています。 ドロップされた時の file 対象は

- 子供として存在する
- for 属性で id が指定されている

です。つまり label ⇔ input の関係と同じです（W3C 違反だが気にしない）。 指定された file の files プロパティが更新され、 change イベントが発火されます。つまり、普通に選択した状況と全く同じになります。

file が見つかる/見つからないに関わらず `.vfile-dropzone` 自体に filedrop というイベントがディスパッチされます。 これは file を使用せずにプレビューを行いたい場合などで使えます。

##### vnode

[](#vnode)

DOM に `data-vnode` という属性を与えると値を用いてレンダリングされます。ちょっとしたテキストを埋め込むには便利です。 ただし、実装は js のテンプレートリテラルを動的に実行しています。 非常に遅い上、危険な文字列が来ると致命的なことになるので十分注意してください。 本格的にやるなら vuejs 等のリアクティブなライブラリを使いましょう。

属性値にはテンプレートリテラルのタグを指定します。通常は Chmonos.Utils.htmlTemplateTag を与えます。 これは html エスケープ付きのタグですが、一部特殊な処理があります。

- 属性に bool(false) が来た場合、属性自体が消える
    - テンプレートリテラルには式が使えるので、かなりの拡張性があるが「無かったこと」にすることだけはできない
    - そして残念ながら html には disabled や hidden などの「値に応じて無かったこと」にしたい処理が多い
    - 要するに `` として enabled で属性の出し分けができるということ

この特殊処理は将来的に拡張される可能性が高いです。

#### バリデーション

[](#バリデーション)

上記でレンダリングした form タグで submit を行った先で下記のようにバリデーションします。

```
// 普通に検証
$isvalid = $form->validate($_POST);
$messages = $form->getMessages();

// 駄目だった場合に例外
$form->validateOrThrow($_POST);
```

上記の通り、2通りの方法があります。

- validate
    - 検証結果を bool で返します
    - エラーメッセージは getMessages で受け取ります
    - 引数は参照渡しなので `$_POST` などを直接渡さないように注意する必要があります
- validateOrThrow
    - 検証して駄目だった場合に `ValidationException` を投げます
    - 返り値として新しい値を返します

基本的には validateOrThrow を推奨します。 参照渡しはハンドリングしにくいし、検証エラーが起こった場合の処理は画一的であり、投げっぱなしの例外をフレームワークなどの共通処理部でハンドリングすればそれで事足りるからです。

なお、参照渡しだったり新しい値を返したりするのは本ライブラリは値の正規化も兼ねるという思想によるものです。 例えばルール外のキーを伏せる、 type=file をファイルパス・オブジェクトにする、デフォルト値で埋める、など、「単に値を検証するだけ」では不便であり、その後「正しい値」が得られると便利です。 つまり、「検証するとともに完全に valid な値が得られる」がコンセプトとして存在します。

下記のようにすると condition によらない独自のエラーを追加できます。

```
// 完全カスタムエラーの追加
$form->error('element_name', 'エラーメッセージ');
```

いずれにせよ、エラーのハンドリングは必要ありません。 validate を通した後の form のレンダリングにエラー表示や値戻しが実装されているので、基本的に何もしなくても OK です。

明示的にエラーが得たい場合は `getMessages` `getFlatMessages` などのメソッドを使います。

### context と template と vuefor

[](#context-と-template-と-vuefor)

ルールの `inputs` 指定を行うとネスト構造が表現できます。 `inputs` を設定すると `element[-1][subelement]` のような name 属性で生成され、「ある特定のフィールドに紐づくフィールドセット」が定義できます。 これをレンダリングするには下記の context/template/vuefor メソッドを使用する必要があります。

なお、下記の記述では断りのない限り

```
[
    'parent' => [
        'inputs' => [
            'child1' => [
                'title'     => '要素1',
            ],
            'child2' => [
                'title'     => '要素2',
            ],
        ]
    ]
]
```

というルールが記述されているものとします。

#### context

[](#context)

指定した連番に応じてフィールドセットを生成します。 開き/閉じは form と同様「引数ありで開き/引数なしで閉じ」です。

```
