フォーム検証
必須コントロール
必須コントロールは setRequired() メソッドでマークします。その引数は、ユーザーがコントロールに入力しなかった場合に表示されるエラーメッセージのテキストです。引数を指定しない場合は、デフォルトのエラーメッセージが使用されます。
$form->addText('name', '名前:') ->setRequired('名前を入力してください'); ルール
検証ルールは addRule() メソッドを使用してコントロールに追加します。最初のパラメータはルール、2番目はエラーメッセージのテキスト、3番目は検証ルールの引数です。
$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 を必要とします。ファイルまたは画像が必要なタイプであるかどうかは、その署名に基づいて検出され、ファイル全体の整合性は検証されません。 画像が破損していないかどうかは、例えば読み込みを試みることで確認できます。
エラーメッセージ
Pattern と PatternInsensitive を除くすべての事前定義されたルールにはデフォルトのエラーメッセージがあるため、省略できます。ただし、すべてのメッセージをカスタマイズして記述することで、フォームはよりユーザーフレンドリーになります。
デフォルトのメッセージは、設定で、Nette\Forms\Validator::$messages 配列内のテキストを編集するか、トランスレータを使用することで変更できます。
エラーメッセージのテキストでは、次のプレースホルダー文字列を使用できます:
%d | ルールの引数で順次置き換えられます |
%n$d | ルールの n 番目の引数で置き換えられます |
%label | コントロールのラベルで置き換えられます(コロンなし) |
%name | コントロールの名前で置き換えられます(例:name) |
%value | ユーザーが入力した値で置き換えられます |
$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() メソッドを使用し、もちろんエラーメッセージは指定しません(条件は単に問い合わせるだけです):
$form->addPassword('password', 'パスワード:') // パスワードが8文字より長くない場合 ->addCondition($form::MaxLength, 8) // 数字を含まなければならない ->addRule($form::Pattern, '数字を含める必要があります', '.*[0-9].*'); 条件は、addConditionOn() を使用して現在のコントロール以外のコントロールにバインドすることもできます。最初のパラメータとして、コントロールへの参照を指定します。この例では、チェックボックスがチェックされた場合(その値が true になる場合)にのみ、メールが必須になります:
$form->addCheckbox('newsletters', 'ニュースレターを購読する'); $form->addEmail('email', 'Eメール:') // チェックボックスがチェックされている場合 ->addConditionOn($form['newsletters'], $form::Equal, true) // メールを要求する ->setRequired('メールアドレスを入力してください'); elseCondition() と endCondition() を使用して、条件から複雑な構造を作成できます:
$form->addText(/* ... */) ->addCondition(/* ... */) // 最初の条件が満たされた場合 ->addConditionOn(/* ... */) // そして別のコントロールの2番目の条件 ->addRule(/* ... */) // このルールを要求する ->elseCondition() // 2番目の条件が満たされない場合 ->addRule(/* ... */) // これらのルールを要求する ->addRule(/* ... */) ->endCondition() // 最初の条件に戻る ->addRule(/* ... */); Nette では、toggle() メソッドを使用して、JavaScript 側で条件の充足または不充足に非常に簡単に対応できます。詳細はダイナミック JavaScriptを参照してください。
他のコントロールへの参照
ルールまたは条件の引数として、フォームの別のコントロールを渡すことができます。ルールは、後でユーザーがブラウザで入力した値を使用します。このようにして、例えば、password コントロールが password_confirm コントロールと同じ文字列を含むことを動的に検証できます:
$form->addPassword('password', 'パスワード'); $form->addPassword('password_confirm', 'パスワードを確認') ->addRule($form::Equal, '入力されたパスワードが一致しません', $form['password']); カスタムルールと条件
Nette の組み込み検証ルールでは不十分で、ユーザーからのデータを独自の方法で検証する必要がある状況に陥ることがあります。Nette ではこれは非常に簡単です!
addRule() または addCondition() メソッドに、最初のパラメータとして任意のコールバックを渡すことができます。コールバックは、最初のパラメータとしてコントロール自体を受け取り、検証が正常に行われたかどうかを示すブール値を返します。addRule() を使用してルールを追加する場合、追加の引数を指定することもでき、それらは2番目のパラメータとして渡されます。
したがって、静的メソッドを持つクラスとして独自のバリデーターセットを作成できます:
class MyValidators { // 値が引数で割り切れるかどうかをテストします public static function validateDivisibility(BaseControl $input, $arg): bool { return $input->getValue() % $arg === 0; } public static function validateEmailDomain(BaseControl $input, $domain) { // 他のバリデーター } } 使用方法は非常に簡単です:
$form->addInteger('num') ->addRule( [MyValidators::class, 'validateDivisibility'], '値は %d の倍数でなければなりません', 8, ); カスタム検証ルールは JavaScript にも追加できます。条件は、ルールが静的メソッドであることです。JavaScript バリデーター用の名前は、バックスラッシュ \ を含まないクラス名、アンダースコア _、およびメソッド名を連結して作成されます。例えば、App\MyValidators::validateDivisibility は AppMyValidators_validateDivisibility として記述され、Nette.validators オブジェクトに追加されます:
Nette.validators['AppMyValidators_validateDivisibility'] = (elem, args, val) => { return val % args === 0; }; onValidate イベント
フォームが送信されると、検証が実行され、addRule() を使用して追加された個々のルールがチェックされ、その後 イベント onValidate がトリガーされます。そのハンドラは、追加の検証、通常は複数のフォームコントロールの値の正しい組み合わせの検証に使用できます。
エラーが検出された場合、addError() メソッドを使用してフォームに渡します。これは、特定のコントロールまたはフォーム自体で呼び出すことができます。
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() メソッドを使用してエラーをフォームに再度渡します。これは、特定のコントロールまたはフォーム自体で呼び出すことができます:
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('無効なパスワードです。'); } } 可能であれば、エラーをフォームコントロールに直接添付することをお勧めします。デフォルトのレンダラーを使用すると、その隣に表示されるためです。
$form['date']->addError('申し訳ありませんが、この日付は既に予約されています。'); addError() を繰り返し呼び出して、フォームまたはコントロールに複数のエラーメッセージを渡すことができます。getErrors() を使用して取得します。
注意:$form->getErrors() は、個々のコントロールに直接渡されたものも含め、すべてのエラーメッセージの要約を返します。フォームにのみ渡されたエラーメッセージは $form->getOwnErrors() で取得できます。
入力の変更
addFilter() メソッドを使用して、ユーザーが入力した値を変更できます。この例では、郵便番号のスペースを許容し、削除します:
$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 ページに埋め込むことができます:
<script src="https://unpkg.com/nette-forms@3"></script> または、プロジェクトの公開フォルダにローカルにコピーします(例:vendor/nette/forms/src/assets/netteForms.min.js から):
<script src="/path/to/netteForms.min.js"></script> または、npm を介してインストールします:
npm install nette-forms そして、ロードして実行します:
import netteForms from 'nette-forms'; netteForms.initOnLoad(); あるいは、vendor フォルダから直接ロードすることもできます:
import netteForms from '../path/to/vendor/nette/forms/src/assets/netteForms.js'; netteForms.initOnLoad(); ダイナミック JavaScript
ユーザーが商品を郵送で送ることを選択した場合にのみ、住所入力フィールドを表示したいですか?問題ありません。キーは addCondition() と toggle() のペアです:
$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 メソッドを独自のソリューションで上書きするだけです:
Nette.toggle = (selector, visible, srcElement, event) => { document.querySelectorAll(selector).forEach((el) => { // 'visible' の値に応じて 'el' を非表示または表示します }); }; 検証の無効化
検証を無効にすると便利な場合があります。送信ボタンの押下が検証を実行しないようにする場合(CancelまたはPreviewボタンに適しています)、$submit->setValidationScope([]) メソッドで無効にします。部分的な検証のみを実行する場合は、検証するフィールドまたはフォームコンテナを指定できます。
$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 イベントは、このコンテナが部分検証用にマークされている場合にのみトリガーされます。