[Drupal]ノードフォームのバリデーションを一時的に無効にする
今回はノードのフォームにこんなボタンを追加してみます。
- クリックするとノードが保存される
- フォームの内容が本来バリデーションに引掛かるようなものでもそのまま保存できる
いわゆる「一時保存」ボタン(?)ですね。
ただし、タイトルは入力しないとDrupal\Core\Entity\EntityStorageException: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'title' cannot be null:
というエラーで画面真っ白になるのでバリデーションを残す必要があります。
いろいろ試したのですが、自分の場合最終的に以下のようなコードになりました。
/**
* Implements hook_form_FORM_ID_alter().
*/
function my_module_form_node_form_alter(&$form, $form_state, $form_id) {
// デフォルトの保存ボタンの内容をコピーする.
$form['actions']['save_as_draft'] = $form['actions']['submit'];
// ラベルを変更する.
$form['actions']['save_as_draft']['#value'] = '一時保存';
// HTML5のバリデーションをオフにする.
$form['#attributes']['novalidate'] = 'novalidate';
// タイトル以外のバリデーションを無効化するハンドラーを追加.
$form['actions']['save_as_draft']['#validate'][] = '_my_module_clear_errors';
}
function _my_module_clear_errors(&$form, $form_state) {
// タイトルのエラーを取得する.
$title_error = $form_state->getError($form['title']['widget'][0]['value']);
// エラーを削除する.
$form_state->clearErrors();
// タイトルのエラーがある場合は元に戻す.
if ($title_error) {
$form_state->setErrorByName('title][0][value', $title_error);
}
// タイトルのエラーが無い場合はバリデーションが完了したことにする.
else {
$form_state->setTemporaryValue('entity_validated', TRUE);
}
}
タイトルのエラーを残す処理が入ってるのでややこしいんですが、要点をまとめると以下のようになります。まず、hook_form_FORM_ID_alter
でボタンを追加します。今回はノードのフォームに追加したいので、FORM_ID
はnode_form
になります。
/**
* Implements hook_form_FORM_ID_alter().
*/
function my_module_form_node_form_alter(&$form, $form_state, $form_id) {
// デフォルトの保存ボタンの内容をコピーする.
$form['actions']['save_as_draft'] = $form['actions']['submit'];
// ラベルを変更する.
$form['actions']['save_as_draft']['#value'] = '一時保存';
}
hook_form_FORM_ID_alterのドキュメント
form idの探し方
この状態で一時保存ボタンを押すとHTML5の必須チェックが動いて邪魔なので、
こちらのコードでオフにしています。(フォーム全体のHTML5のバリデーションがオフになります。)
// HTML5のバリデーションをオフにする.
$form['#attributes']['novalidate'] = 'novalidate';
これでDrupalのバリデーションが反応している状態になります。この時点で一時保存ボタンはラベル以外保存ボタンと同一なので、画像のようにバリデーションエラーが出て保存出来ない状態です。
このバリデーションをオフにするには、
// タイトル以外のバリデーションを無効化するハンドラーを追加.
$form['actions']['save_as_draft']['#validate'][] = '_my_module_clear_errors';
でバリデーションハンドラーを追加します。これで一時保存ボタンクリック時に_my_module_clear_errors
が呼び出されるようになります。_my_module_clear_errors
の中では、
// エラーを削除する.
$form_state->clearErrors();
でバリデーション時に出たエラーを全て無かったことにしています。(今回はカスタムモジュールが一個だけなので大丈夫ですが、いくつものモジュールがバリデーションハンドラーを追加してる場合は、この処理が一番最後に来るようにする必要があります。)
ただし、Drupalの仕様上、単純にバリデーションを消すだけだとentity_validated
というフラグがFALSEのままなので、ノードのpresaveの段階でDrupal\Core\Entity\EntityStorageException: Entity validation was skipped.
という例外がスローされてしまいます。そのため、最後に
$form_state->setTemporaryValue('entity_validated', TRUE);
でバリデーションが完了したことにしています。
タイトルのエラーは
// タイトルのエラーを取得する.
$title_error = $form_state->getError($form['title']['widget'][0]['value']);
でいったん退避させて、
// タイトルのエラーがある場合は元に戻す.
if ($title_error) {
$form_state->setErrorByName('title][0][value', $title_error);
}
で元に戻しています。
public function FormState::getError
public function FormState::setErrorByName
これで一時保存ボタンを押すと、タイトル以外のフィールドでエラーがあっても何も出ません。タイトルだけ入力すればバリデーションをスルーして保存することができます。
というわけで、ノードフォームのバリデーションを一時的に無効にする方法でした。
Author And Source
この問題について([Drupal]ノードフォームのバリデーションを一時的に無効にする), 我々は、より多くの情報をここで見つけました https://qiita.com/863/items/c642449f452f43004eaf著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .