web-dev-qa-db-fra.com

Comment ajouter un gestionnaire de validation personnalisé à un formulaire / champ existant?

Comment ajouter un gestionnaire de validation personnalisé à un formulaire (ou champ de formulaire) existant dans Drupal 8?

J'ai un formulaire que je n'ai pas créé. Je souhaite ajouter mes propres règles de validation sur certains champs lors de l'envoi du formulaire.

Pour Drupal 7, Validation personnalisée pour un formulaire? explique comment implémenter hook_form_alter() puis ajouter votre gestionnaire de validation] [1] à $form['#validate'] Tableau, mais dans Drupal 8 formes sont des classes. La validation se fait par la méthode validateForm() et je ne sais pas comment y brancher mon code.

24
AngularChef

Le #validate property est toujours utilisé dans Drupal 8. (Avec la solution d'Adi, vous remplacerez le validateur existant)

Si vous souhaitez ajouter votre validateur personnalisé en plus de celui par défaut, vous devrez ajouter quelque chose comme ceci dans hook_form_FORM_ID_alter (ou similaire):

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

Berdir a donné la bonne réponse, à savoir qu'une contrainte est la bonne façon de procéder pour ajouter une validation à un champ dans Drupal 8. Voici un exemple.

Dans l'exemple ci-dessous, je vais travailler avec un nœud de type podcast, qui a le champ de valeur unique field_podcast_duration. La valeur de ce champ doit être formatée en HH: MM: SS (heures, minutes et secondes).

Pour créer une contrainte, deux classes doivent être ajoutées. Le premier est la définition de contrainte, et le second est le validateur de contrainte. Ces deux sont des plugins, dans l'espace de noms de Drupal\[MODULENAME]\Plugin\Validation\Constraint.

Tout d'abord, la définition de la contrainte. Notez que l'ID du plugin est donné comme 'PodcastDuration', dans l'annotation (commentaire) de la classe. Cela sera utilisé plus bas.

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';
}

Ensuite, nous devons fournir le validateur de contraintes. Ce nom de cette classe sera le nom de la classe ci-dessus, avec Validator ajouté à lui:

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]);
    }
  }
}

Enfin, nous devons dire à Drupal d'utiliser notre contrainte sur field_podcast_duration Sur le type de nœud podcast. Nous le faisons dans 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

La façon correcte de le faire pour une entité de contenu comme un nœud est de l'enregistrer en tant que contrainte.

Voir forum_entity_bundle_field_info_alter() et le correspondant? ForumLeaf contrainte de validation (notez que deux classes sont nécessaires).

C'est un peu plus compliqué au début, mais l'avantage est qu'il est intégré à l'API de validation, donc votre validation n'est pas limitée au système de formulaire mais peut, par exemple, également fonctionner avec des nœuds soumis via le REST.

17
Berdir

Je veux ajouter un peu plus de lumière sur cette question. L'ajout de la validation est exactement le même que précédemment: dans hook_form_alter:

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

L'utilisation de l'objet values ​​à l'intérieur de $ form_state dans la fonction de validation est cependant un peu différente. par exemple.:

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'));
     }

  }
}

Donc pas avec un accès direct à l'objet de variables privées, mais plutôt avec une fonction getter.

pour plus d'informations, vous pouvez voir un exemple complet dans mon github: https://github.com/flesheater/drupal8_modules_experiments/blob/master/webham_formvalidation/webham_formvalidation.module

à votre santé!

10
Nikolay Borisov

C'est à peu près la même chose qu'en D7. Un exemple complet:

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

En complément de ces bonnes réponses, j'ajouterais:

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

C'est comment appeler une méthode de classe distante pour une validation de formulaire. Je pense que c'est mieux que d'appeler une fonction ci-dessus dans le fichier de module comme dans l'exemple donné.

3
Pauleau

vous pouvez utiliser le module Validation côté client . Quelques détails supplémentaires (à partir de sa page de projet):

... ajoute la validation côté client (également appelée "validation de formulaire Ajax") pour tous les formulaires et formulaires Web à l'aide de jquery.validate . Le fichier jquery.validate.js inclus est corrigé car nous devions pouvoir masquer les messages vides.

1
Mohammed ATIFI