Как добавить пользовательский обработчик проверки в существующую форму / поле?


21

Как добавить собственный обработчик проверки в существующую форму (или поле формы) в Drupal 8?

У меня есть форма, которую я не создал. Я хочу добавить свои собственные правила проверки для некоторых полей при отправке формы.

Для Drupal 7, Пользовательская проверка формы? объясняет, как реализовать, hook_form_alter()а затем добавить ваш обработчик проверки] [1] в $form['#validate']массив, но в Drupal 8 формы являются классами. Проверка выполняется с помощью validateForm()метода, и я не знаю, как подключить мой код к этому.



1
Это не совсем дубликат. У меня вопрос к D8, ваша ссылка для D7.
— AngularChef

Я сталкивался с этим сегодня и просто хотел отметить для других, что вы не используете POST (я хотел отправить URL-адрес на существующую страницу просмотра), ни validateForm, ни submitForm. Оглядываясь назад, это очевидно .... но я потратил 30 минут, пытаясь понять это, прежде чем понял ...: /
— ben.hamelin

Ответы:


19

Это #validateсвойство все еще используется в Drupal 8. (С помощью решения Adi вы переопределите существующий валидатор)

Если вы хотите добавить свой пользовательский валидатор в дополнение к стандартному, вы должны добавить что-то вроде этого в hook_form_FORM_ID_alter (или аналогичный):

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

Спасибо, Шабир. Таким образом, добавление собственного валидатора работает точно так же в D7 и D8. ;)
— AngularChef

Точно, обратитесь к коду модуля узла. там много примеров
— Шабир А.

2
Я только что попробовал, и это сработало отлично, спасибо. Обратите внимание, что вопреки тому, что указано в Справочнике по API формы D8 #validate(ваша ссылка), вы должны использовать $form_stateне массив (способ D7), а объект, реализующий FormStateInterface(способ D8). Другими словами, код в вашем пользовательском валидаторе должен быть аналогом кода, который вы найдете в оригинальном validateForm()методе.
— AngularChef

25

Бердир дал правильный ответ, что ограничение - это правильный путь добавления валидации к полю в Drupal 8. Вот пример.

В приведенном ниже примере я буду работать с узлом типа podcast, который имеет поле с одним значением field_podcast_duration. Значение для этого поля должно быть отформатировано как ЧЧ: ММ: СС (часы, минуты и секунды).

Чтобы создать ограничение, необходимо добавить два класса. Первый - это определение ограничения, а второй - это валидатор ограничения. Оба они являются плагинами в пространстве имен Drupal\[MODULENAME]\Plugin\Validation\Constraint.

Во-первых, определение ограничения. Обратите внимание, что идентификатор плагина задан как «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();

    // If there is no value we don't need to validate anything
    if (!isset($item)) {
      return NULL;
    }

    // Check that the value is in the format HH:MM:SS
    if (!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 использовать наше ограничение field_podcast_durationна podcastтип узла. Мы делаем это в 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');
  }
}

Если вам в итоге понадобятся другие значения поля для проверки вашего поля, вы можете добавить ограничение к типу контента. Смотрите это сообщение в блоге: lakshminp.com/entity-validation-drupal-8-part-2
— ummdorian

1
API проверки формы D8 подробно объясняется на Drupal.org здесь. Предоставление пользовательского ограничения проверки
— Сукхиндер Сингх

1
Поскольку этот вопрос конкретно касается API формы, а не API поля, как можно связать это ограничение с элементом формы (а не с полем сущности)?
— Аарон Бауман

Элементы формы не могут иметь ограничений. Вы можете добавить проверку к определенному элементу формы, используя #element_validate. Посмотрите верхний ответ в этой теме - в D8 он работает так же, как и в D7 drupal.stackexchange.com/questions/86990/…
— Jaypan

Убедитесь, что вы проверили $item = $items->first();и вернули NULL, если ничего не существует, иначе вы получите фатальную ошибку при редактировании поля: TypeError: Аргумент 2, переданный в Drupal \ Component \ Utility \ NestedArray :: getValue (), должен иметь тип массива, дано ноль, вызывается в /data/app/core/lib/Drupal/Core/Field/WidgetBase.php в строке 407 в Drupal \ Component \ Utility \ NestedArray :: getValue () (строка 69 в core / lib / Drupal / Component /Utility/NestedArray.php).
— Иван Зугец,

16

Правильный способ сделать это для объекта содержимого, такого как узел, - зарегистрировать его как ограничение.

Видишь forum_entity_bundle_field_info_alter()и соответствующий? ForumLeafограничение проверки (обратите внимание, что нужны два класса).

Сначала это немного сложнее, но преимущество заключается в том, что он интегрирован в API валидации, поэтому ваша валидация не ограничивается системой форм, но может, например, работать и с узлами, отправленными через REST API.


Хорошая мысль: это что-то новое для тех, кто писал код для Drupal 7. Я уверен, что есть много пользователей, которые попытаются добавить обработчики проверки, когда ограничение будет более подходящим.
— kiamlaluno

Бердир: Я исследовал эту опцию, пытаясь реализовать hook_entity_bundle_field_info_alter()(как описано здесь ), но она никогда не работала ... Кажется, есть задокументированная проблема с этим хуком: drupal.org/node/2346347 .
— AngularChef

Есть некоторые проблемы, но я не думаю, что они связаны с вашей проблемой. forum.module показывает, что это работает. Поделитесь своим кодом, иначе невозможно указать на возможные проблемы в вашей реализации.
— Бердир

1
Я хотел бы пойти с этим методом, но пока есть хороший пример того, как использовать его с типами данных (то есть не специфичными для полей), чтобы проверить, выполняется ли какое-то внешнее условие, я застрял с изменениями формы. Статья не копалась в этом. Может ли кто-нибудь указать мне что-нибудь полезное или опубликовать здесь? Благодарю.
— Колан

что если нам нужно добавить существующую проверку, например \ Drupal \ user \ Form \ UserLoginForm :: validateName (). В d7 это было просто как $ form ['# validate'] = array ('user_login_name_validate', 'myother_validaion',); Но, похоже, модуль no-contrib реализовал эти изменения. Drupal.org/node/2185941
— kiranking

8

Я хочу добавить немного света по этому вопросу. Добавление валидации точно такое же, как и раньше: в hook_form_alter:

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

Использование объекта values ​​внутри $ form_state в функции validate немного отличается. например:

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_experiment/blob/master/webham_formvalidation/webham_formvalidation.module

ура!


В самом деле. Так же, как я написал в своем комментарии выше. ;)
— AngularChef

7

Это очень похоже на 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
}

Это довольно близко. Только hook_form_FORM_ID_alterнужен идентификатор формы. Пользовательская функция проверки может быть любой, какой вы захотите. Кроме того, следуйте инструкциям API здесь для правильных параметров.
— mikeDOTexe

До этого как узнать идентификатор формы, где проверить этот код.
— Логешваран

3

В дополнение к этим хорошим ответам я бы добавил:

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

Это как вызвать метод удаленного класса для проверки формы. Я думаю, что лучше, чем вызывать вышеуказанную функцию в файле модуля, как в приведенном примере.


Больше нет необходимости переходить в процедурный код из ОО.
— Колан

1

Вы можете использовать модуль проверки клиента . Еще несколько подробностей об этом (со страницы проекта):

... добавляет проверку на стороне клиента (также известную как «Проверка формы Ajax») для всех форм и веб- форм, использующих jquery.validate . Включенный файл jquery.validate.js пропатчен, потому что нам нужно было иметь возможность скрывать пустые сообщения.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.