如何在Drupal 8中向现有表单(或表单字段)添加自定义验证处理程序?
我有一个尚未创建的表单。提交表单后,我想在某些字段上添加自己的验证规则。
对于Drupal 7,表单的自定义验证?解释了如何实现hook_form_alter()
并向$form['#validate']
阵列添加验证处理程序] [1] ,但在Drupal 8中,表格是类。验证是通过validateForm()
方法完成的,我不知道如何将代码插入其中。
如何在Drupal 8中向现有表单(或表单字段)添加自定义验证处理程序?
我有一个尚未创建的表单。提交表单后,我想在某些字段上添加自己的验证规则。
对于Drupal 7,表单的自定义验证?解释了如何实现hook_form_alter()
并向$form['#validate']
阵列添加验证处理程序] [1] ,但在Drupal 8中,表格是类。验证是通过validateForm()
方法完成的,我不知道如何将代码插入其中。
Answers:
该#validate
属性仍在Drupal 8中使用。(使用Adi的解决方案,您将覆盖现有的验证器)
如果要在默认值之外添加自定义验证器,则必须在hook_form_FORM_ID_alter(或类似名称)中添加以下内容:
$form['#validate'][] = 'my_test_validate';
#validate
(您的链接)所说的相反,您不应将其$form_state
用作数组(D7方式),而应将其用作实现FormStateInterface
(D8方式)的对象。换句话说,您的自定义验证器中的代码应类似于您在原始validateForm()
方法中找到的代码。
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_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');
}
}
$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)。
对诸如节点之类的内容实体执行此操作的正确方法是将其注册为约束。
看到forum_entity_bundle_field_info_alter()
和对应的?ForumLeaf
验证约束(请注意,需要两个类)。
起初这有点复杂,但是好处是它已集成到验证API中,因此您的验证不仅限于表单系统,而且还可以与通过REST API提交的节点一起使用。
hook_entity_bundle_field_info_alter()
(如描述在这里),但它从来没有工作......似乎有一个记录的问题与此挂钩:drupal.org/node/2346347。
我想对此做更多介绍。验证的添加与之前完全相同:在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
干杯!
它与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
}
您可以使用客户端验证模块。有关它的更多详细信息(从其项目页面):
...使用jquery.validate为所有表单和Web表单添加客户端验证(也称为“ Ajax表单验证”)。修补了包含的jquery.validate.js文件,因为我们需要能够隐藏空消息。