Jak dodać niestandardową procedurę sprawdzania poprawności do istniejącego formularza / pola?

21

Jak dodać niestandardową procedurę sprawdzania poprawności do istniejącego formularza (lub pola formularza) w Drupal 8?

Mam formularz, którego nie utworzyłem. Chcę dodać własne reguły sprawdzania poprawności w niektórych polach po przesłaniu formularza.

W przypadku Drupal 7 niestandardowe sprawdzenie poprawności formularza? wyjaśnia, jak zaimplementować, hook_form_alter()a następnie dodać moduł obsługi sprawdzania poprawności] [1] do $form['#validate']tablicy, ale w formularzach Drupal 8 są klasy. Sprawdzanie poprawności odbywa się za pomocą validateForm()metody i nie wiem, jak podłączyć do tego mój kod.

AngularChef
źródło
4
Możliwy duplikat niestandardowej weryfikacji formularza?
bummi
1
To nie jest dokładnie duplikat. Moje pytanie dotyczy D8, twój link dotyczy D7.
AngularChef
Zetknąłem się z tym dzisiaj i chciałem tylko zwrócić uwagę na inne osoby, jeśli nie korzystasz z POST (chciałem przesłać adres URL do istniejącej strony widoku) ani z funkcją validateForm, ani z submForm. Z perspektywy czasu jest to oczywiste .... ale spędziłem 30 minut, próbując to
rozgryźć

Odpowiedzi:

19

#validateNieruchomość jest nadal używany w Drupal 8. (Z roztworu ADI można zastąpić istniejący walidator)

Jeśli chcesz dodać niestandardowy walidator oprócz domyślnego, musisz dodać coś takiego w hook_form_FORM_ID_alter (lub podobnym):

$form['#validate'][] = 'my_test_validate';
Shabir A.
źródło
Dzięki Shabir. Tak więc dodanie niestandardowego walidatora działa tak samo w D7 i D8. ;)
AngularChef,
Dokładnie sprawdź kod modułu węzła. istnieje wiele przykładów
Shabir A.
2
Właśnie próbowałem i działało idealnie, dziękuję. Należy pamiętać, że w przeciwieństwie do tego, co mówi Dokumentacja interfejsu API formularza D8 dla #validate(twój link), nie należy używać go $form_statejako tablicy (sposób D7), ale jako obiekt implementujący FormStateInterface(sposób D8). Innymi słowy, kod w niestandardowym walidatorze powinien być analogiczny do kodu, który można znaleźć w oryginalnej validateForm()metodzie.
AngularChef,
25

Berdir podał poprawną odpowiedź, że ograniczenie jest właściwą drogą do dodania sprawdzania poprawności do pola w Drupal 8. Oto przykład.

W poniższym przykładzie będę pracował z węzłem typu podcast, który ma pole pojedynczej wartości field_podcast_duration. Wartość tego pola musi być sformatowana jako GG: MM: SS (godziny, minuty i sekundy).

Aby utworzyć ograniczenie, należy dodać dwie klasy. Pierwszy to definicja ograniczenia, a drugi to walidator ograniczenia. Oba są wtyczkami w przestrzeni nazw Drupal\[MODULENAME]\Plugin\Validation\Constraint.

Po pierwsze, definicja ograniczenia. Zauważ, że identyfikator wtyczki jest podany jako „PodcastDuration” w adnotacji (komentarzu) klasy. Zostanie to wykorzystane w dalszej części.

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

Następnie musimy podać moduł sprawdzania poprawności ograniczeń. Ta nazwa tej klasy będzie nazwą klasy z góry, z Validatordołączonym do niej:

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

Wreszcie, musimy powiedzieć Drupal do korzystania z naszego ograniczenia w field_podcast_durationsprawie podcastrodzaju węzła. Robimy to w 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');
  }
}
Jaypan
źródło
Jeśli w końcu potrzebujesz innych wartości pól do sprawdzenia poprawności pola, możesz dodać ograniczenie do typu zawartości. Zobacz ten post na blogu: lakshminp.com/entity-validation-drupal-8-part-2
ummdorian,
1
Interfejs API walidacji D8 został szczegółowo wyjaśniony na Drupal.org tutaj. Zapewnienie niestandardowego ograniczenia sprawdzania poprawności
Sukhjinder Singh
1
Ponieważ pytanie dotyczy konkretnie interfejsu API formularza, a nie interfejsu API pola, w jaki sposób można dołączyć to ograniczenie do elementu formularza (a nie pola encji)?
aaronbauman
Elementy formularza nie mogą mieć ograniczeń. Możesz dodać sprawdzanie poprawności do określonego elementu formularza za pomocą #element_validate. Zobacz najwyższą odpowiedź w tym wątku - działa tak samo w D8, jak w D7 drupal.stackexchange.com/questions/86990/...
Jaypan
Upewnij się, że $item = $items->first();zaznaczyłeś i zwróciłeś NULL, jeśli nic tam nie ma, inaczej wystąpi błąd krytyczny podczas edycji pola: TypeError: Argument 2 przekazany do Drupal \ Component \ Utility \ NestedArray :: getValue () musi być tablicy typów, podana null, wywołana w /data/app/core/lib/Drupal/Core/Field/WidgetBase.php w linii 407 w Drupal \ Component \ Utility \ NestedArray :: getValue () (linia 69 rdzenia / lib / Drupal / Component /Utility/NestedArray.php).
Ivan Zugec
16

Prawidłowym sposobem na to dla jednostki treści takiej jak węzeł jest zarejestrowanie jej jako ograniczenia.

Widzisz forum_entity_bundle_field_info_alter()i odpowiadające? ForumLeafograniczenie sprawdzania poprawności (należy pamiętać, że potrzebne są dwie klasy).

Na początku jest to nieco bardziej skomplikowane, ale zaletą jest to, że jest zintegrowane z interfejsem API do sprawdzania poprawności, dzięki czemu sprawdzanie poprawności nie ogranicza się do systemu formularzy, ale może na przykład także współpracować z węzłami przesłanymi za pośrednictwem interfejsu API REST.

Berdir
źródło
Dobra uwaga: jest to coś nowego dla osób, które pisały kod dla Drupala 7. Jestem pewien, że istnieje wielu użytkowników, którzy spróbują dodać procedury sprawdzania poprawności, gdy ograniczenie będzie bardziej odpowiednie.
kiamlaluno
Berdir: Badałem tę opcję, próbując ją wdrożyć hook_entity_bundle_field_info_alter()(jak opisano tutaj ), ale nigdy nie działała ... Wygląda na to, że istnieje udokumentowany problem z tym hakiem: drupal.org/node/2346347 .
AngularChef,
Istnieją pewne problemy, ale nie sądzę, że są one związane z twoim problemem. forum.module pokazuje, że to działa. Udostępnij swój kod, w przeciwnym razie nie będzie możliwe wskazanie możliwych problemów w implementacji.
Berdir,
1
Chciałbym skorzystać z tej metody, ale dopóki nie będzie dobrego przykładu jej użycia z typami danych (tj. Nie specyficznymi dla pola), aby sprawdzić, czy spełniony jest jakiś warunek zewnętrzny, utknąłem w formularzu. Artykuł nie zagłębił się w to. Czy ktoś uprzejmie wskaże mi jakieś przydatne miejsce lub opublikuje je tutaj? Dzięki.
colan
co jeśli musimy dodać istniejące sprawdzanie poprawności, takie jak \ Drupal \ user \ Form \ UserLoginForm :: validateName (). W wersji d7 było to proste: $ form ['# validate'] = array ('user_login_name_validate', 'myother_validaion',); Ale wygląda na to, że moduł no-contrib zaimplementował te zmiany drupal.org/node/2185941
kiranking
8

Chcę dodać nieco więcej światła na ten temat. Dodanie sprawdzania poprawności jest dokładnie takie samo jak poprzednio: w hook_form_alter:

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

Użycie obiektu wartości wewnątrz $ form_state w funkcji sprawdzania poprawności jest nieco inne. na przykład:

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

  }
}

Więc nie z bezpośrednim dostępem do obiektu zmiennych prywatnych, ale raczej z funkcją gettera.

Aby uzyskać więcej informacji, możesz zobaczyć pełny przykład w moim github: https://github.com/flesheater/drupal8_modules_experiments/blob/master/webham_formvalidation/webham_formvalidation.module

Twoje zdrowie!

Nikołaj Borysow
źródło
Rzeczywiście jest. Tak jak napisałem w moim komentarzu powyżej. ;)
AngularChef
7

Jest bardzo podobny do tego w D7. Kompletny przykład:

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
}
nicholas.alipaz
źródło
To jest dość blisko. Potrzebny jest tylko hook_form_FORM_ID_alteridentyfikator formularza. Możesz mieć niestandardową funkcję sprawdzania poprawności dowolną. Należy również postępować zgodnie z instrukcją API tutaj, aby uzyskać odpowiednie parametry.
mikeDOTexe,
Wcześniej, jak uzyskać identyfikator formularza, gdzie sprawdzić ten kod.
logeshvaran
3

W uzupełnieniu tych dobrych odpowiedzi dodałbym:

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

To jak wywołać metodę klasy odległej w celu sprawdzenia poprawności formularza. Myślę, że lepiej jest wywołać powyższą funkcję w pliku modułu, tak jak w podanym przykładzie.

Pauleau
źródło
Nie ma już potrzeby przeskakiwania do kodu proceduralnego z OO.
Colan
1

możesz użyć modułu weryfikacji klienta . Kilka dodatkowych szczegółów na ten temat (ze strony projektu):

... dodaje sprawdzanie poprawności po stronie klienta (zwane również „sprawdzaniem poprawności formularza Ajax”) dla wszystkich formularzy i formularzy internetowych za pomocą jquery.validate . Dołączony plik jquery.validate.js został załatany, ponieważ musieliśmy być w stanie ukryć puste wiadomości.

Mohammed ATIFI
źródło