web-dev-qa-db-ja.com

カスタム検証ハンドラを既存のフォーム/フィールドに追加するにはどうすればよいですか?

Drupal 8)の既存のフォーム(またはフォームフィールド)にカスタム検証ハンドラーを追加するにはどうすればよいですか?

作成していないフォームがあります。フォームが送信されたときに、いくつかのフィールドに独自の検証ルールを追加したいと思います。

Drupal 7、の場合 フォームのカスタム検証? は、hook_form_alter()を実装し、検証ハンドラ] [1]を_$form['#validate']_配列、ただしDrupal 8フォームはクラスです。検証はvalidateForm()メソッドを介して行われ、コードをそれにプラグインする方法がわかりません。

24
AngularChef

#validate property は、引き続きDrupal 8で使用されています。(Adiのソリューションでは、既存のバリデータをオーバーライドします)

デフォルトに加えてカスタムバリデーターを追加する場合は、次のように hook_form_FORM_ID_alter (または同様の)に追加する必要があります。

$form['#validate'][] = 'my_test_validate';
19
Shabir A.

Berdirは正しい答えを出しました。制約はDrupal 8のフィールドに検証を追加するための正しい方法です。ここに例があります。

以下の例では、_field_podcast_duration_という単一の値フィールドを持つpodcastタイプのノードを使用します。このフィールドの値は、HH:MM:SS(時間、分、秒)の形式にする必要があります。

制約を作成するには、2つのクラスを追加する必要があります。 1つ目は制約定義で、2つ目は制約バリデーターです。これらは両方とも_Drupal\[MODULENAME]\Plugin\Validation\Constraint_の名前空間のプラグインです。

まず、制約の定義です。プラグインIDは、クラスの注釈(コメント)で「PodcastDuration」として指定されることに注意してください。これはさらに下で使用されます。

_namespace Drupal\[MODULENAME]\Plugin\Validation\Constraint;

use Symfony\Component\Validator\Constraint;

/**
 * Checks that the submitted duration is of the format HH:MM:SS
 *
 * @Constraint(
 *   id = "PodcastDuration",
 *   label = @Translation("Podcast Duration", context = "Validation"),
 * )
 */
class PodcastDurationConstraint extends Constraint {

  // The message that will be shown if the format is incorrect.
  public $incorrectDurationFormat = 'The duration must be in the format HH:MM:SS or HHH:MM:SS. You provided %duration';
}
_

次に、制約バリデーターを提供する必要があります。このクラスのこの名前は、上からのクラス名にValidatorが追加されたものになります。

_namespace Drupal\[MODULENAME]\Plugin\Validation\Constraint;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;

/**
 * Validates the PodcastDuration constraint.
 */
class PodcastDurationConstraintValidator extends ConstraintValidator {

  /**
   * {@inheritdoc}
   */
  public function validate($items, Constraint $constraint) {
    // This is a single-item field so we only need to
    // validate the first item
    $item = $items->first();

    // Check that the value is in the format HH:MM:SS
    if ($item && !preg_match('/^[0-9]{1,2}:[0-5]{1}[0-9]{1}:[0-5]{1}[0-9]{1}$/', $item->value)) {
      // The value is an incorrect format, so we set a 'violation'
      // aka error. The key we use for the constraint is the key
      // we set in the constraint, in this case $incorrectDurationFormat.
      $this->context->addViolation($constraint->incorrectDurationFormat, ['%duration' => $item->value]);
    }
  }
}
_

最後に、Drupalにpodcastノードタイプの_field_podcast_duration_に制約を使用するように指示する必要があります。これはhook_entity_bundle_field_info_alter()で行います:

_use Drupal\Core\Entity\EntityTypeInterface;

function HOOK_entity_bundle_field_info_alter(&$fields, EntityTypeInterface $entity_type, $bundle) {
  if (!empty($fields['field_podcast_duration'])) {
    $fields['field_podcast_duration']->addConstraint('PodcastDuration');
  }
}
_
27
Jaypan

ノードなどのコンテンツエンティティに対してこれを行う正しい方法は、それを制約として登録することです。

forum_entity_bundle_field_info_alter()および対応する?を参照してください。 ForumLeaf検証制約(2つのクラスが必要であることに注意してください)。

最初は少し複雑ですが、利点は検証APIに統合されているため、検証はフォームシステムに限定されず、REST AP​​I。

17
Berdir

この問題についてもう少し詳しく説明したいと思います。検証の追加は以前とまったく同じです:hook_form_alter:

$form['#validate'][] = '_form_validation_number_title_validate';

検証関数の$ form_state内の値オブジェクトの使用は少し異なりますが。例えば。:

function _form_validation_number_title_validate(&$form, \Drupal\Core\Form\FormStateInterface $form_state) {

  if ($form_state->hasValue('title')) {
     $title = $form_state->getValue('title');

     if (!is_numeric($title[0]['value'])) {
        $form_state->setErrorByName('title', t('Your title should be number'));
     }

  }
}

したがって、プライベート変数オブジェクトへの直接アクセスではなく、ゲッター関数を使用します。

詳細については、私のgithubで完全な例を見ることができます: https://github.com/flesheater/drupal8_modules_experiments/blob/master/webham_formvalidation/webham_formvalidation.module

乾杯!

10
Nikolay Borisov

D7とほとんど同じです。完全な例:

mymodule.module

use Drupal\Core\Form\FormStateInterface;

/**
 * Implements hook_form_FORM_ID_alter() for the FORM_ID() form.
 */
function mymodule_form_FORM_ID_alter(&$form, FormStateInterface $form_state, $form_id) {
  $form['#validate'][] = '_mymodule_form_FORM_ID_validate';
}

/**
 * Validates submission values in the FORM_ID() form.
 */
function _mymodule_form_FORM_ID_validate(array &$form, FormStateInterface $form_state) {
  // Validation code here
}
6
nicholas.alipaz

これらの良い答えを補完するために、私は追加します:

$form['#validate'][] = 'Drupal\your_custom_module_name\CustomClass::customValidate';

これは、フォーム検証のために遠くのクラスメソッドを呼び出す方法です。与えられた例のようにモジュールファイルで上記の関数を呼び出すよりも良いと思います。

3
Pauleau

Clientside Validation モジュールを使用できます。それのいくつかの詳細(プロジェクトページから):

... jquery.validate を使用して、すべてのフォームとWebフォームにクライアントサイド検証(別名 "Ajaxフォーム検証")を追加します。空のメッセージを非表示にする必要があるため、含まれているjquery.validate.jsファイルにパッチを適用しました。

1
Mohammed ATIFI