Özel bir doğrulama işleyicisini varolan bir forma / alana nasıl eklerim?


21

Özel bir doğrulama işleyicisini Drupal 8'deki varolan bir forma (veya form alanına) nasıl eklerim?

Oluşturmadığım bir formum var. Form gönderildiğinde bazı alanlara kendi geçerlilik kurallarını eklemek istiyorum.

Drupal 7 için, Bir form için özel doğrulama? hook_form_alter()Doğrulama işleyicinizi] [1] $form['#validate']dizisine uygulayıp sonra eklemeyi açıklar , ancak Drupal 8 formları sınıflardır. Doğrulama validateForm()yöntem aracılığıyla yapılır ve kodumu buna nasıl ekleyeceğimi bilmiyorum.



1
Bu tam olarak bir kopya değil. Benim sorum D8 için, bağlantınız D7 için.
AngularChef

Bugün bununla karşılaştım ve POST kullanmıyorsanız (varolan bir görünüm sayfasına bir URL gönderilmesini istedim), ne validateForm ne de cancelForm çalıştırması için başkalarına not vermek istedim. Gördüğümde bu açık ... ama farkına varmadan önce anlamaya çalışarak 30 dakikamı harcadım ....: /
ben.hamelin

Yanıtlar:


19

#validateMülkiyet hala Drupal 8. kullanılmaktadır (Adi'nin çözümü ile mevcut doğrulayıcı geçersiz kılar)

Özel validatörünüzü varsayılana ek olarak eklemek isterseniz, hook_form_FORM_ID_alter (veya benzeri) içine böyle bir şey eklemeniz gerekir :

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

Sağol Shabir. Dolayısıyla, özel bir onaylayıcı eklemek D7 ve D8'de aynı şekilde çalışır. ;)
AngularChef

Aynen, düğüm modülünün koduna bakın. Orada birçok örnek var
Shabir A.

2
Sadece denedim ve mükemmel çalıştı, teşekkür ederim. Lütfen D8 Form API Referansının #validate(bağlantınız) için söylediklerinin aksine $form_state, bir dizi (D7 yolu) olarak değil, bir nesne uygulaması FormStateInterface(D8 yolu) olarak kullanmanız gerektiğini unutmayın . Başka bir deyişle, özel onaylayıcınızdaki kod, orijinal bir validateForm()yöntemde bulacağınız kodla aynı olmalıdır .
AngularChef

25

Berdir doğru cevabı verdi, bir kısıtlamanın Drupal 8'deki bir alana doğrulama eklemeye devam etmenin doğru yolu olduğunu söyledi. İşte bir örnek.

Aşağıdaki örnekte podcast, tek değer alanına sahip bir tür düğümle çalışacağım field_podcast_duration. Bu alan için değer HH: MM: SS (saat, dakika ve saniye) olarak biçimlendirilmelidir.

Bir kısıtlama oluşturmak için iki sınıfın eklenmesi gerekir. Birincisi, kısıtlama tanımı ve ikincisi de kısıtlama doğrulayıcısıdır. Bunların her ikisi de isim alanı olan eklentilerdir Drupal\[MODULENAME]\Plugin\Validation\Constraint.

İlk olarak, kısıt tanımı. Eklenti kimliğinin, sınıfın ek açıklamasında (yorumunda) 'PodcastDuration' olarak verildiğini unutmayın. Bu daha aşağı kullanılacaktır.

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

Sonra, kısıtlayıcı doğrulayıcıyı sağlamamız gerekir. Bu sınıfın bu adı, üzerine Validatoreklenmiş olarak yukarıdan bir sınıf adı olacaktır :

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

Son olarak, bizim kısıtlamayı kullanmak Drupal'i anlatmaya gerek field_podcast_durationilgili podcastdüğüm türü. Bunu biz yapıyoruz 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');
  }
}

Alanınızı doğrulamak için başka alan değerlerine ihtiyaç duyarsanız, içerik türüne bir sınırlama ekleyebilirsiniz. Bu blog gönderisine bakın: lakshminp.com/entity-validation-drupal-8-part-2
ummdorian 13:17

1
D8 Form Validasyon API'si burada Drupal.org sitesinde detaylı olarak açıklanmıştır. Özel bir doğrulama kısıtı sağlama
Sukhjinder Singh

1
Bu soru özellikle Alan API'si değil Form API ile ilgili olduğundan, bu kısıtlama bir form öğesine (varlık alanı değil) nasıl eklenir?
aaronbauman

Form öğelerinin kısıtları olamaz. #Element_validate kullanarak belirli bir form öğesine doğrulama ekleyebilirsiniz. Bu konudaki en iyi cevabı gör
D8'de

$item = $items->first();Hiçbir şey yoksa NULL’u kontrol edip geri döndürdüğünüzden emin olun, aksi takdirde alanı düzenlerken önemli bir hatayla karşılaşacaksınız: TypeError: Argument 2, Drupal \ Component \ Utility \ NestedArray :: getValue () öğesine geçildi. verilen değer / Drupal \ Component \ Utility \ NestedArray :: getValue () satırındaki 407 satırındaki /data/app/core/lib/Drupal/Core/Field/WidgetBase.php adresinde (çekirdek / lib / Drupal / Component satır 69) /Utility/NestedArray.php).
Ivan Zugec

16

Bunu, düğüm benzeri bir içerik varlığı için yapmanın doğru yolu, onu bir kısıtlama olarak kaydetmektir.

Bakın forum_entity_bundle_field_info_alter()ve karşılık gelen? ForumLeafdoğrulama kısıtlaması (gerekli iki sınıf olduğuna dikkat edin).

Bu ilk bakışta biraz daha karmaşık olmakla birlikte, bunun avantajı doğrulama API'sine entegre edilmiş olmasıdır, bu nedenle onaylamanız form sistemiyle sınırlı değildir, örneğin REST API aracılığıyla gönderilen düğümlerle de çalışabilir.


İyi nokta: Bu, Drupal 7 için kod yazan kişiler için yeni bir şeydir. Bir kısıtlama daha uygun olduğunda doğrulama işleyicileri eklemeye çalışacak birçok kullanıcı olduğundan eminim.
kiamlaluno

Berdir: Bu seçeneği uygulamaya çalışarak araştırdım hook_entity_bundle_field_info_alter()( burada açıklandığı gibi ) ama hiç işe yaramadı ... Bu kancayla ilgili belgelenmiş bir sorun var gibi görünüyor: drupal.org/node/2346347 .
AngularChef,

Bazı sorunlar var ama onların sorununuzla ilgili olduğunu sanmıyorum. forum.module çalıştığını gösterir. Kodunuzu paylaşın, aksi halde uygulamanızdaki olası sorunları belirtmek mümkün değildir.
Berdir

1
Bu yöntemle devam etmek isterim, ancak bazı dış koşulların karşılanıp karşılanmadığını kontrol etmek için veri türleriyle (yani alana özgü değil) nasıl kullanılacağına dair iyi bir örnek oluncaya kadar, form değişmeleriyle sıkışıp kaldım. Makale bu konuya girmedi. Biri nazikçe bana yararlı bir yere işaret eder mi yoksa buraya postalar mı? Teşekkürler.
kola

\ Drupal \ user \ Form \ UserLoginForm :: validateName () gibi mevcut bir doğrulama eklememiz gerekirse. D7'de $ form ['# validate'] = array ('user_login_name_validate', 'myother_validaion',); Ama modülü uygulamaya no-contrib bu değişiklikler görünüyor drupal.org/node/2185941
kiranking

8

Bu konuda biraz daha ışık eklemek istiyorum. Doğrulamanın eklenmesi aynen öncekiyle aynıdır: hook_form_alter:

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

Validate fonksiyonunda $ form_state içindeki değerler nesnesinin kullanımı biraz farklı olsa da. Örneğin:

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

  }
}

Dolayısıyla, özel değişkenler nesnesine doğrudan erişimle değil, daha çok bir alıcı işleviyle.

daha fazla bilgi için github'ımda tam bir örnek görebilirsiniz: https://github.com/flesheater/drupal8_modules_experiments/blob/master/webham_formvalidation/webham_formvalidation.module

şerefe!


Gerçekten öyle. Tıpkı yukarıdaki yorumuma yazdığım gibi. ;)
AngularChef

7

D7'deki ile aynı. Tam bir örnek:

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
}

Bu oldukça yakın. Sadece hook_form_FORM_ID_alterkimliğe ihtiyaç vardır. Özel doğrulama fonksiyonunun istediğiniz herhangi bir şey olmasını sağlayabilirsiniz. Ayrıca, uygun parametreler için buradaki API kılavuzunu izleyin .
mikeDOTexe

Bundan önce, form kimliğini nasıl alırsınız, bu kodu nerede kontrol edersiniz.
logeshvaran

3

Bu iyi cevapların tamamlayıcısı olarak şunu ekleyeceğim:

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

Form doğrulama için uzak bir sınıf yönteminin nasıl çağırılacağıdır. Modül dosyasında yukarıdaki örnekte olduğu gibi yukarıdaki işlevi çağırmak daha iyi olur.


OO'dan prosedür koduna geçmeye artık gerek yok.
Kasım’da

1

Clientside Validation modülünü kullanabilirsiniz . Bununla ilgili bazı detaylar (proje sayfasından):

... jquery.validate kullanarak tüm formlar ve web formları için müşteri doğrulama (aka "Ajax form doğrulama") ekler . Dahil edilen jquery.validate.js dosyası, boş mesajları gizleyebilmemiz gerektiğinden yamalıdır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.