-
-
Notifications
You must be signed in to change notification settings - Fork 277
Expand file tree
/
Copy pathvalidation.texy
More file actions
376 lines (268 loc) · 18.7 KB
/
validation.texy
File metadata and controls
376 lines (268 loc) · 18.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
フォーム検証
******
必須コントロール
========
必須コントロールは `setRequired()` メソッドでマークします。その引数は、ユーザーがコントロールに入力しなかった場合に表示される[#エラーメッセージ]のテキストです。引数を指定しない場合は、デフォルトのエラーメッセージが使用されます。
```php
$form->addText('name', '名前:')
->setRequired('名前を入力してください');
```
ルール
===
検証ルールは `addRule()` メソッドを使用してコントロールに追加します。最初のパラメータはルール、2番目は[#エラーメッセージ]のテキスト、3番目は検証ルールの引数です。
```php
$form->addPassword('password', 'パスワード:')
->addRule($form::MinLength, 'パスワードは少なくとも %d 文字必要です', 8);
```
**検証ルールは、ユーザーがコントロールに入力した場合にのみ検証されます。**
Nette には、`Nette\Forms\Form` クラスの定数である名前を持つ、多数の事前定義されたルールが付属しています。すべてのコントロールでこれらのルールを使用できます:
| 定数 | 説明 | 引数の型
|-------
| `Required` | 必須コントロール、`setRequired()` のエイリアス | -
| `Filled` | 必須コントロール、`setRequired()` のエイリアス | -
| `Blank` | コントロールは入力してはいけません | -
| `Equal` | 値がパラメータと等しい | `mixed`
| `NotEqual` | 値がパラメータと等しくない | `mixed`
| `IsIn` | 値が配列内のいずれかの項目と等しい | `array`
| `IsNotIn` | 値が配列内のどの項目とも等しくない | `array`
| `Valid` | コントロールは正しく入力されていますか? ([#条件]用) | -
テキスト入力
------
`addText()`、`addPassword()`、`addTextArea()`、`addEmail()`、`addInteger()`、`addFloat()` コントロールでは、次のルールのいくつかを使用することもできます:
| `MinLength` | テキストの最小長 | `int`
| `MaxLength` | テキストの最大長 | `int`
| `Length` | 範囲内の長さまたは正確な長さ | ペア `[int, int]` または `int`
| `Email` | 有効なメールアドレス | -
| `URL` | 絶対URL | -
| `Pattern` | 正規表現に一致する | `string`
| `PatternInsensitive` | `Pattern` と同様ですが、大文字と小文字を区別しません | `string`
| `Integer` | 整数値 | -
| `Numeric` | `Integer` のエイリアス | -
| `Float` | 数値 | -
| `Min` | 数値コントロールの最小値 | `int\|float`
| `Max` | 数値コントロールの最大値 | `int\|float`
| `Range` | 範囲内の値 | ペア `[int\|float, int\|float]`
検証ルール `Integer`、`Numeric`、`Float` は、値をそれぞれ整数または浮動小数点数に直接変換します。さらに、ルール `URL` はスキーマのないアドレス(例:`nette.org`)も受け入れ、スキーマを追加します(`https://nette.org`)。`Pattern` と `PatternIcase` の式は、値全体に対して有効でなければなりません。つまり、`^` と `$` 文字で囲まれているかのように扱われます。
項目数
---
`addMultiUpload()`、`addCheckboxList()`、`addMultiSelect()` コントロールでは、選択された項目またはアップロードされたファイルの数を制限するために、次のルールを使用することもできます:
| `MinLength` | 最小数 | `int`
| `MaxLength` | 最大数 | `int`
| `Length` | 範囲内の数または正確な数 | ペア `[int, int]` または `int`
ファイルアップロード
----------
`addUpload()`、`addMultiUpload()` コントロールでは、次のルールを使用することもできます:
| `MaxFileSize` | ファイルの最大サイズ(バイト単位) | `int`
| `MimeType` | MIME タイプ、ワイルドカード許可 (`'video/*'`) | `string\|string[]`
| `Image` | JPEG、PNG、GIF、WebP、AVIF 画像 | -
| `Pattern` | ファイル名が正規表現に一致する | `string`
| `PatternInsensitive` | `Pattern` と同様ですが、大文字と小文字を区別しません | `string`
`MimeType` と `Image` は PHP 拡張機能 `fileinfo` を必要とします。ファイルまたは画像が必要なタイプであるかどうかは、その署名に基づいて検出され、**ファイル全体の整合性は検証されません。** 画像が破損していないかどうかは、例えば[読み込み |http:request#toImage]を試みることで確認できます。
エラーメッセージ
========
`Pattern` と `PatternInsensitive` を除くすべての事前定義されたルールにはデフォルトのエラーメッセージがあるため、省略できます。ただし、すべてのメッセージをカスタマイズして記述することで、フォームはよりユーザーフレンドリーになります。
デフォルトのメッセージは、[設定|forms:configuration]で、`Nette\Forms\Validator::$messages` 配列内のテキストを編集するか、[トランスレータ |rendering#翻訳]を使用することで変更できます。
エラーメッセージのテキストでは、次のプレースホルダー文字列を使用できます:
| `%d` | ルールの引数で順次置き換えられます
| `%n$d` | ルールの n 番目の引数で置き換えられます
| `%label` | コントロールのラベルで置き換えられます(コロンなし)
| `%name` | コントロールの名前で置き換えられます(例:`name`)
| `%value` | ユーザーが入力した値で置き換えられます
```php
$form->addText('name', '名前:')
->setRequired('%label を入力してください');
$form->addInteger('id', 'ID:')
->addRule($form::Range, '最小 %d、最大 %d', [5, 10]);
$form->addInteger('id', 'ID:')
->addRule($form::Range, '最大 %2$d、最小 %1$d', [5, 10]);
```
条件
========
ルールに加えて、条件を追加することもできます。これらはルールと同様に記述されますが、`addRule()` の代わりに `addCondition()` メソッドを使用し、もちろんエラーメッセージは指定しません(条件は単に問い合わせるだけです):
```php
$form->addPassword('password', 'パスワード:')
// パスワードが8文字より長くない場合
->addCondition($form::MaxLength, 8)
// 数字を含まなければならない
->addRule($form::Pattern, '数字を含める必要があります', '.*[0-9].*');
```
条件は、`addConditionOn()` を使用して現在のコントロール以外のコントロールにバインドすることもできます。最初のパラメータとして、コントロールへの参照を指定します。この例では、チェックボックスがチェックされた場合(その値が true になる場合)にのみ、メールが必須になります:
```php
$form->addCheckbox('newsletters', 'ニュースレターを購読する');
$form->addEmail('email', 'Eメール:')
// チェックボックスがチェックされている場合
->addConditionOn($form['newsletters'], $form::Equal, true)
// メールを要求する
->setRequired('メールアドレスを入力してください');
```
`elseCondition()` と `endCondition()` を使用して、条件から複雑な構造を作成できます:
```php
$form->addText(/* ... */)
->addCondition(/* ... */) // 最初の条件が満たされた場合
->addConditionOn(/* ... */) // そして別のコントロールの2番目の条件
->addRule(/* ... */) // このルールを要求する
->elseCondition() // 2番目の条件が満たされない場合
->addRule(/* ... */) // これらのルールを要求する
->addRule(/* ... */)
->endCondition() // 最初の条件に戻る
->addRule(/* ... */);
```
Nette では、`toggle()` メソッドを使用して、JavaScript 側で条件の充足または不充足に非常に簡単に対応できます。詳細は[#ダイナミック JavaScript]を参照してください。
他のコントロールへの参照
============
ルールまたは条件の引数として、フォームの別のコントロールを渡すことができます。ルールは、後でユーザーがブラウザで入力した値を使用します。このようにして、例えば、`password` コントロールが `password_confirm` コントロールと同じ文字列を含むことを動的に検証できます:
```php
$form->addPassword('password', 'パスワード');
$form->addPassword('password_confirm', 'パスワードを確認')
->addRule($form::Equal, '入力されたパスワードが一致しません', $form['password']);
```
カスタムルールと条件
==========
Nette の組み込み検証ルールでは不十分で、ユーザーからのデータを独自の方法で検証する必要がある状況に陥ることがあります。Nette ではこれは非常に簡単です!
`addRule()` または `addCondition()` メソッドに、最初のパラメータとして任意のコールバックを渡すことができます。コールバックは、最初のパラメータとしてコントロール自体を受け取り、検証が正常に行われたかどうかを示すブール値を返します。`addRule()` を使用してルールを追加する場合、追加の引数を指定することもでき、それらは2番目のパラメータとして渡されます。
したがって、静的メソッドを持つクラスとして独自のバリデーターセットを作成できます:
```php
class MyValidators
{
// 値が引数で割り切れるかどうかをテストします
public static function validateDivisibility(BaseControl $input, $arg): bool
{
return $input->getValue() % $arg === 0;
}
public static function validateEmailDomain(BaseControl $input, $domain)
{
// 他のバリデーター
}
}
```
使用方法は非常に簡単です:
```php
$form->addInteger('num')
->addRule(
[MyValidators::class, 'validateDivisibility'],
'値は %d の倍数でなければなりません',
8,
);
```
カスタム検証ルールは JavaScript にも追加できます。条件は、ルールが静的メソッドであることです。JavaScript バリデーター用の名前は、バックスラッシュ `\` を含まないクラス名、アンダースコア `_`、およびメソッド名を連結して作成されます。例えば、`App\MyValidators::validateDivisibility` は `AppMyValidators_validateDivisibility` として記述され、`Nette.validators` オブジェクトに追加されます:
```js
Nette.validators['AppMyValidators_validateDivisibility'] = (elem, args, val) => {
return val % args === 0;
};
```
onValidate イベント
===============
フォームが送信されると、検証が実行され、`addRule()` を使用して追加された個々のルールがチェックされ、その後 [イベント |nette:glossary#イベント] `onValidate` がトリガーされます。そのハンドラは、追加の検証、通常は複数のフォームコントロールの値の正しい組み合わせの検証に使用できます。
エラーが検出された場合、`addError()` メソッドを使用してフォームに渡します。これは、特定のコントロールまたはフォーム自体で呼び出すことができます。
```php
protected function createComponentSignInForm(): Form
{
$form = new Form;
// ...
$form->onValidate[] = [$this, 'validateSignInForm'];
return $form;
}
public function validateSignInForm(Form $form, \stdClass $data): void
{
if ($data->foo > 1 && $data->bar > 5) {
$form->addError('この組み合わせは不可能です。');
}
}
```
処理中のエラー
=======
多くの場合、有効なフォームを処理しているときにのみエラーが判明します。例えば、新しい項目をデータベースに書き込んでいるときにキーの重複に遭遇した場合などです。この場合、`addError()` メソッドを使用してエラーをフォームに再度渡します。これは、特定のコントロールまたはフォーム自体で呼び出すことができます:
```php
try {
$data = $form->getValues();
$this->user->login($data->username, $data->password);
$this->redirect('Home:');
} catch (Nette\Security\AuthenticationException $e) {
if ($e->getCode() === Nette\Security\Authenticator::InvalidCredential) {
$form->addError('無効なパスワードです。');
}
}
```
可能であれば、エラーをフォームコントロールに直接添付することをお勧めします。デフォルトのレンダラーを使用すると、その隣に表示されるためです。
```php
$form['date']->addError('申し訳ありませんが、この日付は既に予約されています。');
```
`addError()` を繰り返し呼び出して、フォームまたはコントロールに複数のエラーメッセージを渡すことができます。`getErrors()` を使用して取得します。
注意:`$form->getErrors()` は、個々のコントロールに直接渡されたものも含め、すべてのエラーメッセージの要約を返します。フォームにのみ渡されたエラーメッセージは `$form->getOwnErrors()` で取得できます。
入力の変更
=====
`addFilter()` メソッドを使用して、ユーザーが入力した値を変更できます。この例では、郵便番号のスペースを許容し、削除します:
```php
$form->addText('zip', '郵便番号:')
->addFilter(function ($value) {
return str_replace(' ', '', $value); // 郵便番号からスペースを削除します
})
->addRule($form::Pattern, '郵便番号は5桁の数字ではありません', '\d{5}');
```
フィルタは検証ルールと条件の間に組み込まれるため、メソッドの順序が重要です。つまり、フィルタとルールは `addFilter()` と `addRule()` メソッドの順序で呼び出されます。
JavaScript 検証
=============
条件とルールを定式化するための言語は非常に強力です。すべての構造はサーバー側と JavaScript 側の両方で機能します。 それらは HTML 属性 `data-nette-rules` に JSON として転送されます。実際の検証は、フォームの `submit` イベントをキャッチし、個々のコントロールを反復処理して適切な検証を実行するスクリプトによって行われます。
そのスクリプトは `netteForms.js` であり、複数の可能なソースから利用できます:
スクリプトは CDN から直接 HTML ページに埋め込むことができます:
```latte
<script src="https://unpkg.com/nette-forms@3"></script>
```
または、プロジェクトの公開フォルダにローカルにコピーします(例:`vendor/nette/forms/src/assets/netteForms.min.js` から):
```latte
<script src="/path/to/netteForms.min.js"></script>
```
または、[npm|https://www.npmjs.com/package/nette-forms] を介してインストールします:
```shell
npm install nette-forms
```
そして、ロードして実行します:
```js
import netteForms from 'nette-forms';
netteForms.initOnLoad();
```
あるいは、`vendor` フォルダから直接ロードすることもできます:
```js
import netteForms from '../path/to/vendor/nette/forms/src/assets/netteForms.js';
netteForms.initOnLoad();
```
ダイナミック JavaScript
=================
ユーザーが商品を郵送で送ることを選択した場合にのみ、住所入力フィールドを表示したいですか?問題ありません。キーは `addCondition()` と `toggle()` のペアです:
```php
$form->addCheckbox('send_it')
->addCondition($form::Equal, true)
->toggle('#address-container');
```
このコードは、条件が満たされたとき、つまりチェックボックスがチェックされたときに、HTML 要素 `#address-container` が表示されることを示しています。そしてその逆も同様です。受信者の住所を持つフォームコントロールをこの ID を持つコンテナに配置すると、チェックボックスをクリックすると非表示または表示されます。これはスクリプト `netteForms.js` が保証します。
`toggle()` メソッドの引数として、任意のセレクタを渡すことができます。歴史的な理由から、他の特殊文字を含まない英数字文字列は要素の ID として解釈されます。つまり、`#` 文字が前に付いているのと同じです。2番目のオプションのパラメータを使用すると、動作を反転させることができます。つまり、`toggle('#address-container', false)` を使用した場合、要素はチェックボックスがチェックされていない場合にのみ表示されます。
JavaScript のデフォルトの実装は、要素の `hidden` プロパティを変更します。ただし、例えばアニメーションを追加するなど、動作を簡単に変更できます。JavaScript で `Nette.toggle` メソッドを独自のソリューションで上書きするだけです:
```js
Nette.toggle = (selector, visible, srcElement, event) => {
document.querySelectorAll(selector).forEach((el) => {
// 'visible' の値に応じて 'el' を非表示または表示します
});
};
```
検証の無効化
======
検証を無効にすると便利な場合があります。送信ボタンの押下が検証を実行しないようにする場合(*Cancel*または*Preview*ボタンに適しています)、`$submit->setValidationScope([])` メソッドで無効にします。部分的な検証のみを実行する場合は、検証するフィールドまたはフォームコンテナを指定できます。
```php
$form->addText('name')
->setRequired();
$details = $form->addContainer('details');
$details->addInteger('age')
->setRequired('age');
$details->addInteger('age2')
->setRequired('age2');
$form->addSubmit('send1'); // フォーム全体を検証します
$form->addSubmit('send2')
->setValidationScope([]); // まったく検証しません
$form->addSubmit('send3')
->setValidationScope([$form['name']]); // name コントロールのみを検証します
$form->addSubmit('send4')
->setValidationScope([$form['details']['age']]); // age コントロールのみを検証します
$form->addSubmit('send5')
->setValidationScope([$form['details']]); // details コンテナを検証します
```
`setValidationScope` は、フォームの[#onValidate イベント]には影響しません。これは常に呼び出されます。コンテナの `onValidate` イベントは、このコンテナが部分検証用にマークされている場合にのみトリガーされます。