Як додати спеціальний обробник перевірки до існуючої форми / поля?


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. (С рішенням Аді ви відкидаєте існуючий валідатор)

Якщо ви хочете додати свій власний валідатор на додаток до типового, вам доведеться додати щось подібне у moll_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. Значення для цього поля потрібно відформатувати як HH: MM: SS (години, хвилини та секунди).

Для створення обмеження потрібно додати два класи. Перше - визначення обмеження, а друге - валідатор обмежень. Обидва ці плагіни в просторі імен 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 тут. Забезпечення спеціального обмеження для перевірки
— Sukhjinder Singh

1
Оскільки це питання стосується конкретно API API, а не API API, як можна прив’язати це обмеження до елемента форми (а не до сутності)?
— aaronbauman

Елементи форми не можуть мати обмежень. Ви можете додати перевірку до певного елемента форми за допомогою #element_validate. Дивіться верхню відповідь на цю тему - вона працює так само в D8, як і D7 drupal.stackexchange.com/questions/86990/…
— Jaypan

Переконайтесь, що ви перевіряєте $item = $items->first();та повертаєте NULL, якщо нічого там немає, інакше ви отримаєте фатальну помилку під час редагування поля: TypeError: Аргумент 2, переданий Drupal \ Component \ Utility \ NestedArray :: getValue (), повинен бути типу типу, null задано, викликається в /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 перевірки, тому ваша перевірка не обмежується системою форм, але, наприклад, може також працювати з вузлами, поданими через API REST.


Хороший момент: Це щось нове для тих, хто раніше писав код для 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',); Але, здається , немає-вно реалізований модуль ці зміни НЕ drupal.org/node/2185941
— kiranking

8

Я хочу додати ще трохи світла в цьому питанні. Додавання перевірки точно таке ж, як і раніше: у mock_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'));
     }

  }
}

Отже, не з прямим доступом до об'єкта приватних змінних, а скоріше з функцією getter.

для отримання додаткової інформації ви можете побачити повний приклад у моєму 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

Перед цим як отримати ідентифікатор форми, де перевірити цей код.
— logeshvaran

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.