如何将自定义验证处理程序添加到现有表单/字段?


21

如何在Drupal 8中向现有表单(或表单字段)添加自定义验证处理程序?

我有一个尚未创建的表单。提交表单后,我想在某些字段上添加自己的验证规则。

对于Drupal 7,表单的自定义验证?解释了如何实现hook_form_alter()并向$form['#validate']阵列添加验证处理程序] [1] ,但在Drupal 8中,表格是类。验证是通过validateForm()方法完成的,我不知道如何将代码插入其中。



1
这并非完全重复。我的问题是D8,您的链接是D7。
AngularChef,2013年

我今天碰到了这一点,如果您不使用POST(我想将URL提交到现有视图页面),则只想向其他人说明一下,validateForm或submitForm都不会运行。事后看来,这很明显....但是我花了30分钟试图弄清楚,然后才意识到....:/
ben.hamelin

Answers:


19

#validate属性仍在Drupal 8中使用。(使用Adi的解决方案,您将覆盖现有的验证器)

如果要在默认值之外添加自定义验证器,则必须在hook_form_FORM_ID_alter(或类似名称)中添加以下内容:

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

谢谢,沙比尔。因此,添加自定义验证器在D7和D8中的工作原理相同。;)
AngularChef 2015年

确实,请参考节点模块的代码。那里有很多例子
Shabir A.

2
我刚刚尝试了一下,效果很好,谢谢。请注意,与D8表单API参考#validate(您的链接)所说的相反,您不应将其$form_state用作数组(D7方式),而应将其用作实现FormStateInterface(D8方式)的对象。换句话说,您的自定义验证器中的代码应类似于您在原始validateForm()方法中找到的代码。
AngularChef 2015年

25

Berdir给出了正确的答案,即约束是向Drupal 8中的字段添加验证的正确方法。这是一个示例。

在下面的示例中,我将使用podcast具有单个value字段的type节点field_podcast_duration。该字段的值需要格式化为HH:MM:SS(小时,分钟和秒)。

要创建约束,需要添加两个类。第一个是约束定义,第二个是约束验证器。这两个都是插件,位于的命名空间中Drupal\[MODULENAME]\Plugin\Validation\Constraint

首先,约束定义。请注意,在该类的注释(注释)中,插件ID为'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_durationpodcast节点类型。我们在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
D8表单验证API已在Drupal.org上进行了详细说明。提供自定义验证约束条件
Sukhjinder Singh's

1
由于此问题专门针对表单API,而不是字段API,因此如何将这一约束附加到表单元素(不是实体字段)?
aaronbauman

表单元素不能有约束。您可以使用#element_validate将验证添加到特定的表单元素。请参阅此线程的最佳答案-它在D8中的工作方式与D7drupal.stackexchange.com/questions/86990/…
Jaypan

$item = $items->first();如果没有任何内容,请确保检查并返回NULL,否则在编辑字段时会出现致命错误:TypeError:传递给Drupal \ Component \ Utility \ NestedArray :: getValue()的参数2必须为数组类型,给定null,在Drupal \ Component \ Utility \ NestedArray :: getValue()的第407行的/data/app/core/lib/Drupal/Core/Field/WidgetBase.php中调用(core / lib / Drupal / Component的第69行/Utility/NestedArray.php)。
伊万·祖格

16

对诸如节点之类的内容实体执行此操作的正确方法是将其注册为约束。

看到forum_entity_bundle_field_info_alter()和对应的?ForumLeaf验证约束(请注意,需要两个类)。

起初这有点复杂,但是好处是它已集成到验证API中,因此您的验证不仅限于表单系统,而且还可以与通过REST API提交的节点一起使用。


好处:对于曾经为Drupal 7编写代码的人来说,这是新事物。我确信有很多用户会在约束更合适时尝试添加验证处理程序。
kiamlaluno

Berdir:我也试图通过实施此方法的可行性hook_entity_bundle_field_info_alter()(如描述在这里),但它从来没有工作......似乎有一个记录的问题与此挂钩:drupal.org/node/2346347
AngularChef 2015年

有一些问题,但我认为它们与您的问题无关。forum.module显示它有效。共享您的代码,否则无法指出实现中可能存在的问题。
贝尔迪尔

1
我想使用这种方法,但是直到有一个很好的示例说明如何将其与数据类型(即非特定于字段)一起使用以检查是否满足某些外部条件之前,我仍然坚持使用alters形式。这篇文章没有深入探讨。有人会在我有用的地方指出我的意见,还是将其张贴在这里?谢谢。
科兰

如果我们需要添加现有的验证,例如\ Drupal \ user \ Form \ UserLoginForm :: validateName(),该怎么办。在d7中,这很简单,因为$ form ['#validate'] = array('user_login_name_validate','myother_validaion',); 但是似乎无人参与的模块实现了这些更改drupal.org/node/2185941
排名

8

我想对此做更多介绍。验证的添加与之前完全相同:在hook_form_alter中:

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

在validate函数的$ form_state内部使用values对象有点不同。例如:

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_experiments/blob/master/webham_formvalidation/webham_formvalidation.module

干杯!


它的确是。就像我在上面的评论中写道。;)
AngularChef 2016年

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需要表单ID。您可以使定制验证功能成为您想要的任何东西。另外,请按照此处API指南获取正确的参数。
mikeDOTexe '16

在此之前,以及如何获取表单ID,以及在何处检查此代码。
logeshvaran

3

为了补充这些好的答案,我将添加:

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

这是如何调用远程类方法进行表单验证的方法。我认为最好像在给定的示例中那样在模块文件中调用上述函数。


不再需要从OO跳入程序代码。
科兰

1

您可以使用客户端验证模块。有关它的更多详细信息(从其项目页面):

...使用jquery.validate为所有表单和Web表单添加客户端验证(也称为“ Ajax表单验证”)。修补了包含的jquery.validate.js文件,因为我们需要能够隐藏空消息。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.