作者:老葛,北京亚艾元软件有限责任公司,http://www.yaiyuan.com
但是项目中的实际问题,还是需要解决的。在实际的项目中,章林选择是用了form_alter来解决这个问题。Form_alter我们在前面,Think in Drupal第一集里面的第一章讲的就是这个钩子,它是非常有用的,在这里解决这个问题也是非常有效的。首先确定实体表单的ID,然后通过form_alter为这个表单添加一个验证回调函数,在自己的验证函数里面添加自己的逻辑。原有的代码已经找不到了,我在网络上找了段类似的代码,做了一下改造:
function mymodule_form_alter(&$form, &$form_state, $form_id) {
if ($form_id == 'test_node_form') {
$form['#validate'] = 'mymodule_custom_validation_handler';
}
}
function mymodule_custom_validation_handler((&$form, &$form_state){
$length = strlen($form_state['values']['field_testlength']['und']['0']['value'])
if ($length > 8) {
form_set_error("field_testlength']['und']['0']['value", t('长度必须小于等于8。'));
}
}
这段程序我没有调试,用的时候,自己需要检查一下。这里需要注意的是,获取字段值的方法:
$form_state['values']['field_testlength']['und']['0']['value']
以及设置错误消息时,第一个参数:
"field_testlength']['und']['0']['value"
另一个需要注意的是,字段的语言属性,['und'],这里究竟是用und还是默认语言,用的时候也需要自己检查一下。
我觉得,解决Drupal7下面的字段验证,应该有更好一点的钩子,我便寻找,寻找,终于找到了一个可能工作的钩子。我的解决办法是这样的:
/**
* Implements hook_field_attach_validate().
*/
function field_validation_field_attach_validate($entity_type, $entity, &$errors) {
list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
if($entity_type =='node' && $bundle = 'test'){
if($field_text = $entity->field_text){
if(strlen($field_text['und'][0]['value'])>8){
$errors['field_text']['und'][0][] = array(
'error' => 'field_text',
'message' => t('length must less than 8.'),
);
}
}
}
}
这是最原始的测试代码,它仅仅用来说明了hook_field_attach_validate是可以用来解决这个问题。这也是我第一次使用这个钩子函数。而以后,有关Field的验证问题,一直都是通过这个钩子解决的。首先,我觉得这种方式比form_alter高级一点,Dries曾经写过一篇介绍Drupal7的文章,里面就讲到了字段的验证,与表单的验证分离开了,这在Drupal7里面是一个进步。而这种分离,在Drupal8里面还会进一步的改进。我在drupal.org上面贡献了field validation模块以后,曾经有人建议使用Form_alter的形式,但是我没有理他们,还是坚持使用hook_field_attach_validate。
另外的值得注意的是,这段代码:
list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
这是我从别处拷贝过来的。这里根据一个实体对象、还有实体类型,使用entity_extract_ids这个API函数,便可以提取出来它的id、vid、bundle。这是很有用的,但是有时候,这个API函数并不能正常工作,个别时候,大部分都是可以的。
此外,这个错误消息的设置:
$errors['field_text']['und'][0][] = array(
'error' => 'field_text',
'message' => t('length must less than 8.'),
);
这个,我们在第一集的,字段API一章里面介绍过了这个结构。我最初编写的时候,并不知道这两个键的含义,尤其是'error',所以默认把它设置为了字段名字。'message'的含义我是清楚的,用来设置具体的错误消息。
代码并不是一下子就工作了,我还做了很多的调试工作。还是使用原始的drupal_set_message和debug。
有了hook_field_attach_validate,我们便不需要考虑具体的表单ID了,因为内容类型很多,实体类型也很多。我们不可能处理所有的情况,而hook_field_attach_validate可以帮助我们从这个问题中解脱出来。我在选用这个钩子以前,应该读过Field Attach API,http://api.drupal.org/api/drupal/modules%21field%21field.attach.inc/group/field_attach/7,以及http://api.drupal.org/api/drupal/modules%21field%21field.module/group/field/7, 当然,我还在api.drupal.org上面搜索相关的钩子函数:
它的触发函数,field_attach_validate,我应该也读过的:
function field_attach_validate($entity_type, $entity) {
$errors = array();
// Check generic, field-type-agnostic errors first.
_field_invoke_default('validate', $entity_type, $entity, $errors);
// Check field-type specific errors.
_field_invoke('validate', $entity_type, $entity, $errors);
// Let other modules validate the entity.
// Avoid module_invoke_all() to let $errors be taken by reference.
foreach (module_implements('field_attach_validate') as $module) {
$function = $module . '_field_attach_validate';
$function($entity_type, $entity, $errors);
}
if ($errors) {
throw new FieldValidationException($errors);
}
}
我读的时候不够细致,忽略里面的注释。总之,我做了很多的准备工作的。