Làm cách nào để thêm trình xử lý xác thực tùy chỉnh vào biểu mẫu / trường hiện có?


21

Làm cách nào để thêm trình xử lý xác thực tùy chỉnh vào biểu mẫu hiện có (hoặc trường biểu mẫu) trong Drupal 8?

Tôi có một hình thức mà tôi chưa tạo ra. Tôi muốn thêm quy tắc xác thực của riêng mình vào một số trường khi biểu mẫu được gửi.

Đối với Drupal 7, xác thực tùy chỉnh cho một biểu mẫu? giải thích để thực hiện hook_form_alter()và sau đó thêm trình xử lý xác nhận của bạn] [1] vào $form['#validate']mảng, nhưng trong biểu mẫu Drupal 8 là các lớp. Xác thực được thực hiện thông qua validateForm()phương thức và tôi không biết cách cắm mã của mình vào đó.



1
Nó không chính xác là một bản sao. Câu hỏi của tôi là dành cho D8, liên kết của bạn là dành cho D7.
AngularChef

Tôi đã bắt gặp điều này ngày hôm nay và chỉ muốn lưu ý cho những người khác nếu bạn không sử dụng POST (tôi muốn gửi URL tới trang xem hiện tại) không phải làateateForm cũng không phải là submitForm chạy. Nhìn chung, điều này là hiển nhiên .... nhưng tôi đã dành 30 phút để cố gắng tìm ra nó trước khi tôi nhận ra ....: /
ben.hamelin

Câu trả lời:


19

Các #validatebất động sản vẫn được sử dụng trong Drupal 8. (Với giải pháp Adi của bạn sẽ ghi đè lên các validator hiện có)

Nếu bạn muốn thêm trình xác nhận tùy chỉnh của mình ngoài mặc định, bạn sẽ phải thêm một cái gì đó như thế này trong hook_form_FORM_ID_alter (hoặc tương tự):

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

Cảm ơn, Shabir. Vì vậy, việc thêm trình xác nhận tùy chỉnh hoạt động giống nhau trong D7 và D8. ;)
AngularChef

Chính xác, tham khảo mã của mô-đun nút. có rất nhiều ví dụ ở đó
Shabir A.

2
Tôi chỉ thử nó và nó hoạt động hoàn hảo, cảm ơn bạn. Xin lưu ý rằng trái với những gì Tham chiếu API mẫu D8 nói #validate(liên kết của bạn), bạn không nên sử dụng $form_statenhư một mảng (cách D7), mà là một đối tượng triển khai FormStateInterface(cách D8). Nói cách khác, mã trong trình xác nhận tùy chỉnh của bạn phải giống với mã bạn tìm thấy trong một validateForm()phương thức ban đầu .
AngularChef

25

Berdir đã đưa ra câu trả lời chính xác, rằng một ràng buộc là cách chính xác để tiến tới việc thêm xác nhận vào một trường trong Drupal 8. Dưới đây là một ví dụ.

Trong ví dụ dưới đây, tôi sẽ làm việc với một nút loại podcast, có trường giá trị đơn field_podcast_duration. Giá trị cho trường này cần được định dạng là HH: MM: SS (giờ, phút và giây).

Để tạo một ràng buộc, hai lớp cần phải được thêm vào. Đầu tiên là định nghĩa ràng buộc và thứ hai là trình xác nhận ràng buộc. Cả hai đều là plugin, trong không gian tên của Drupal\[MODULENAME]\Plugin\Validation\Constraint.

Đầu tiên, định nghĩa ràng buộc. Lưu ý rằng ID plugin được cung cấp dưới dạng 'PodcastDuration', trong chú thích (nhận xét) của lớp. Điều này sẽ được sử dụng hơn nữa xuống.

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

Tiếp theo, chúng ta cần cung cấp trình xác nhận ràng buộc. Tên của lớp này sẽ là tên lớp ở trên, được Validatorgắn vào nó:

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

Cuối cùng, chúng ta cần phải nói với Drupal sử dụng hạn chế của chúng tôi trên field_podcast_durationtrên podcastloại nút. Chúng tôi làm điều này trong 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');
  }
}

Nếu bạn cuối cùng cần các giá trị trường khác để xác thực trường của bạn, bạn có thể thêm một ràng buộc cho loại nội dung. Xem bài đăng trên blog này: lakshminp.com/entity-validation-drupal-8-part-2
ummdorian

1
API xác thực mẫu D8 đã được giải thích chi tiết trên Drupal.org tại đây. Cung cấp một ràng buộc xác thực tùy chỉnh
Sukhjinder Singh

1
Vì câu hỏi này cụ thể về API biểu mẫu, không phải API trường, làm thế nào để đính kèm ràng buộc này với một phần tử biểu mẫu (không phải trường thực thể)?
aaronbauman

Các yếu tố hình thức không thể có các ràng buộc. Bạn có thể thêm xác thực cho một thành phần biểu mẫu cụ thể bằng cách sử dụng #element_validate. Xem câu trả lời hàng đầu về chủ đề này - nó hoạt động tương tự trong D8 như D7 drupal.stackexchange.com/questions/86990/ mẹo
Jaypan

Hãy chắc chắn rằng bạn kiểm tra $item = $items->first();và trả lại NULL nếu không có gì nếu không bạn sẽ gặp phải lỗi nghiêm trọng khi chỉnh sửa trường: TypeError: Đối số 2 được chuyển cho Drupal \ Component \ Utility \ NestedArray :: getValue () phải thuộc mảng kiểu, null được cung cấp, được gọi trong /data/app/core/lib/Drupal/Core/Field/WidgetBase.php trên dòng 407 trong Drupal \ Component \ Utility \ NestedArray :: getValue () (dòng 69 của core / lib / Drupal / Thành phần /Utility/NestedArray.php).
Ivan Zugec

16

Cách chính xác để làm điều này cho một thực thể nội dung như nút là đăng ký nó như một ràng buộc.

Thấy forum_entity_bundle_field_info_alter()và tương ứng? ForumLeafràng buộc xác nhận (lưu ý rằng có hai lớp cần thiết).

Điều đó phức tạp hơn một chút lúc đầu, nhưng ưu điểm là nó được tích hợp vào API xác thực, do đó, xác thực của bạn không giới hạn ở hệ thống biểu mẫu, ví dụ, cũng có thể hoạt động với các nút được gửi qua API REST.


Điểm hay: Đây là một điều mới mẻ đối với những người đã từng viết mã cho Drupal 7. Tôi chắc chắn có nhiều người dùng sẽ thử thêm trình xử lý xác thực khi một ràng buộc phù hợp hơn.
kiamlaluno

Berdir: Tôi đã khám phá tùy chọn này bằng cách thử thực hiện hook_entity_bundle_field_info_alter()(như được mô tả ở đây ) nhưng nó không bao giờ hoạt động ... Dường như có một vấn đề được ghi lại với cái móc này: drupal.org/node/2346347 .
AngularChef

Có một số vấn đề nhưng tôi không nghĩ chúng có liên quan đến vấn đề của bạn. forum.module cho thấy rằng nó hoạt động. Chia sẻ mã của bạn, không thể chỉ ra các vấn đề có thể xảy ra trong quá trình thực hiện của bạn.
Berdir

1
Tôi muốn sử dụng phương pháp này, nhưng cho đến khi có một ví dụ hay về cách sử dụng nó với các loại dữ liệu (nghĩa là không phải trường cụ thể) để kiểm tra xem có một số điều kiện bên ngoài được đáp ứng hay không, tôi bị mắc kẹt với biểu mẫu thay đổi. Bài báo đã không đi sâu vào vấn đề này. Ai đó vui lòng chỉ cho tôi một nơi hữu ích, hoặc gửi nó ở đây? Cảm ơn.
colan

Điều gì xảy ra nếu chúng ta cần thêm xác thực hiện có như \ Drupal \ user \ Form \ UserLoginForm :: validateName (). Trong d7, nó đơn giản như $ form ['# validate'] = mảng ('user_login_name_validate', 'myother_validaion',); Nhưng có vẻ như mô-đun không đóng góp đã thực hiện những thay đổi này drupal.org/node/2185941
kiranking

8

Tôi muốn thêm một số ánh sáng về vấn đề này. Việc thêm xác thực hoàn toàn giống như trước: trong hook_form_alter:

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

Việc sử dụng các đối tượng giá trị bên trong $ form_state trong hàm xác thực mặc dù có một chút khác biệt. ví dụ:

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

  }
}

Vì vậy, không phải với một truy cập trực tiếp vào đối tượng biến riêng tư, mà là với một hàm getter.

để biết thêm thông tin, bạn có thể xem một ví dụ đầy đủ trong github của tôi: https://github.com/f Meateater/drupal8_modules_experiment/blob/master/webham_formvalidation/webham_formvalidation.module

chúc mừng


Quả thực là như vậy. Giống như tôi đã viết trong bình luận của tôi ở trên. ;)
AngularChef

7

Nó rất giống với trong D7. Một ví dụ hoàn chỉnh:

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
}

Điều này là khá gần. Chỉ hook_form_FORM_ID_altercần ID mẫu. Bạn có thể có chức năng xác nhận tùy chỉnh là bất cứ điều gì bạn muốn. Ngoài ra, hãy làm theo hướng dẫn API ở đây để biết các thông số phù hợp.
mikeDOTexe

Trước đó, làm thế nào để có được id mẫu, kiểm tra mã này ở đâu.
logeshvaran

3

Để bổ sung cho những câu trả lời tốt, tôi sẽ thêm:

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

Đó là cách gọi một phương thức lớp xa để xác thực mẫu. Tôi nghĩ rằng tốt hơn là gọi một hàm trên trong tệp mô-đun như trong ví dụ đã cho.


Không còn cần phải nhảy vào mã thủ tục từ OO.
colan

1

bạn có thể sử dụng mô đun Xác thực khách hàng . Một số chi tiết về nó (từ trang dự án của nó):

... Thêm xác thực khách hàng (còn gọi là "Xác thực mẫu Ajax") cho tất cả các biểu mẫu và biểu mẫu web bằng jquery.validate . Tệp jquery.validate.js đi kèm được vá vì chúng tôi cần có thể ẩn các tin nhắn trống.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.