Drupal Commerce结账:绕过邮箱验证存储文本至数据库的方法
问题描述
匿名访客在Drupal Commerce结账流程的「订单信息」步骤中,需在指定邮箱输入框填写内容,该内容会存入数据库commerce_order表的mail字段。输入框代码如下:
<input data-drupal-selector="edit-contact-information-email" type="email" id="edit-contact-information-email" name="contact_information[email]" value="" size="60" maxlength="254" class="form-email required" required="required" aria-required="true">
尝试通过JS修改输入框文本并将type改为text后,数据仍无法存入数据库,推测存在邮箱验证逻辑。需明确:
- 该验证逻辑在JS或PHP中的位置?
- 如何解决此问题?
解决方案
一、验证逻辑的位置
1. PHP端(核心验证,决定数据是否入库)
Drupal Commerce的订单邮箱验证核心在PHP层,主要分布在这几个位置:
- 结账表单验证:结账流程的表单类(通常是
src/Form/CheckoutForm.php或对应结账流程的表单文件)的validateForm()方法中,会调用邮箱验证器检查格式。 - 实体字段约束:
commerce_order实体的mail字段在src/Entity/Order.php的baseFieldDefinitions()方法里,被定义为EmailItem类型,自带邮箱格式约束;也可能在模块的schema配置文件(config/schema/commerce_order.schema.yml)中定义了格式规则。 - 自定义钩子验证:如果有自定义模块或主题,可能通过
hook_form_alter()或hook_entity_bundle_field_info_alter()添加了额外的邮箱验证规则。
2. JS端(前端拦截,仅阻止表单提交)
前端验证是辅助性的,触发点包括:
- Drupal核心的
core/misc/form.js会识别form-email类,对输入框做前端邮箱格式校验,不符合规则时阻止表单提交。 - Commerce结账流程的专属JS(如
commerce_checkout模块下的js/checkout.js)可能也有额外的前端验证逻辑。
二、解决方法
方法一:修改实体字段约束(推荐,无侵入)
自定义一个模块,通过钩子修改mail字段的类型约束,移除邮箱格式要求:
/** * Implements hook_entity_bundle_field_info_alter(). */ function my_custom_module_entity_bundle_field_info_alter(&$fields, \Drupal\Core\Entity\EntityTypeInterface $entity_type, $bundle) { if ($entity_type->id() === 'commerce_order' && $bundle === 'default' && isset($fields['mail'])) { // 将邮箱字段改为普通字符串类型,保留必填属性 $fields['mail']->setItemDefinition(\Drupal\Core\Field\BaseFieldDefinition::create('string') ->setLabel(t('Contact email')) ->setDescription(t('The contact information.')) ->setRequired(TRUE) ->setDisplayOptions('form', [ 'type' => 'string_textfield', 'weight' => 0, ]) ->setDisplayConfigurable('form', TRUE)); } }
执行后清除Drupal缓存,mail字段即可存储任意文本字符串。
方法二:修改表单验证逻辑
如果只需要针对结账表单取消验证,可通过钩子修改表单的验证规则:
/** * Implements hook_form_FORM_ID_alter(). */ function my_custom_module_form_commerce_checkout_flow_multistep_default_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) { // 移除邮箱字段的验证回调 if (isset($form['contact_information']['email']['#element_validate'])) { unset($form['contact_information']['email']['#element_validate']); } // 替换字段类型为普通文本输入 $form['contact_information']['email']['#type'] = 'textfield'; }
注意:FORM_ID需要替换为你实际使用的结账表单ID,可通过浏览器开发者工具查看表单的id属性获取。
方法三:前后端配合处理
- 前端:用JS移除前端验证标记,取消前端拦截:
document.addEventListener('DOMContentLoaded', function() { const emailInput = document.getElementById('edit-contact-information-email'); if (emailInput) { emailInput.type = 'text'; emailInput.classList.remove('form-email'); // 清除Drupal绑定的验证器 delete emailInput.dataset.drupalValidator; } });
- 后端:配合上述PHP端的修改(方法一或方法二),确保后端不再验证邮箱格式,才能让数据顺利入库。
内容的提问来源于stack exchange,提问作者stckvrw
相关产品推荐
相关产品推荐

