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


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.