mirror of
https://gitee.com/johng/gf
synced 2026-06-06 16:21:40 +08:00
Fixed use cname in gvalid tag.
Added gvaild data type support for array, slice, map. Added array, slice, map data test in gvaild unit test.
This commit is contained in:
@ -7,16 +7,19 @@
|
||||
package gvalid
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/g/container/gmap"
|
||||
"github.com/gogf/gf/g/encoding/gjson"
|
||||
"github.com/gogf/gf/g/net/gipv4"
|
||||
"github.com/gogf/gf/g/net/gipv6"
|
||||
"github.com/gogf/gf/g/os/gtime"
|
||||
"github.com/gogf/gf/g/text/gregex"
|
||||
"github.com/gogf/gf/g/text/gstr"
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -104,7 +107,56 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// 检测单条数据的规则:
|
||||
// 检测单条数据
|
||||
// value数据类型可以为map、array、slice以及其它基本数据类型
|
||||
func Check(value interface{}, rules string, msgs interface{}, params ...interface{}) *Error {
|
||||
|
||||
rv := reflect.ValueOf(value)
|
||||
switch rv.Kind() {
|
||||
case reflect.Array, reflect.Slice: // Array/Slice 遍历调用
|
||||
for i := 0; i < rv.Len(); i++ {
|
||||
err := Check(rv.Index(i).Interface(), rules, msgs, params...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
case reflect.Map: // Map 遍历调用
|
||||
iter := rv.MapRange()
|
||||
for iter.Next() {
|
||||
err := Check(iter.Value().Interface(), rules, msgs, params...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
case reflect.Ptr: // Ptr
|
||||
rv := rv.Elem()
|
||||
array := make([]interface{}, 0)
|
||||
switch rv.Kind() {
|
||||
case reflect.Slice, reflect.Array:
|
||||
for i := 0; i < rv.Len(); i++ {
|
||||
array = append(array, rv.Index(i).Interface())
|
||||
}
|
||||
return Check(array, rules, msgs, params...)
|
||||
case reflect.Struct:
|
||||
rt := rv.Type()
|
||||
for i := 0; i < rv.NumField(); i++ {
|
||||
// Only public attributes.
|
||||
if !gstr.IsLetterUpper(rt.Field(i).Name[0]) {
|
||||
continue
|
||||
}
|
||||
array = append(array, rv.Field(i).Interface())
|
||||
}
|
||||
return Check(array, rules, msgs, params...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return doCheckSingleRule(value, rules, msgs, params...)
|
||||
}
|
||||
|
||||
// 基本数据类型校验
|
||||
//
|
||||
// 1. value为需要校验的数据,可以为任意基本数据类型;
|
||||
//
|
||||
@ -112,7 +164,7 @@ var (
|
||||
// 允许传递多个自定义的错误信息,如果类型为string,那么中间使用"|"符号分隔多个自定义错误;
|
||||
//
|
||||
// 3. params参数为联合校验参数,支持任意的map/struct/*struct类型,对于需要联合校验的规则有效,如:required-*、same、different;
|
||||
func Check(value interface{}, rules string, msgs interface{}, params ...interface{}) *Error {
|
||||
func doCheckSingleRule(value interface{}, rules string, msgs interface{}, params ...interface{}) *Error {
|
||||
// 内部会将参数全部转换为字符串类型进行校验
|
||||
val := strings.TrimSpace(gconv.String(value))
|
||||
data := make(map[string]string)
|
||||
|
||||
@ -10,7 +10,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/g/internal/structs"
|
||||
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
)
|
||||
|
||||
@ -22,6 +21,7 @@ var (
|
||||
// 校验struct对象属性,object参数也可以是一个指向对象的指针,返回值同CheckMap方法。
|
||||
// struct的数据校验结果信息是顺序的。
|
||||
func CheckStruct(object interface{}, rules interface{}, msgs ...CustomMsg) *Error {
|
||||
cname := make(map[string]string) // 别名记录
|
||||
params := make(map[string]interface{})
|
||||
checkRules := make(map[string]string)
|
||||
customMsgs := make(CustomMsg)
|
||||
@ -82,6 +82,8 @@ func CheckStruct(object interface{}, rules interface{}, msgs ...CustomMsg) *Erro
|
||||
name, rule, msg := parseSequenceTag(tagValue)
|
||||
if len(name) == 0 {
|
||||
name = fieldName
|
||||
} else {
|
||||
cname[fieldName] = name
|
||||
}
|
||||
// params参数使用别名**扩容**(而不仅仅使用别名),仅用于验证使用
|
||||
if _, ok := params[name]; !ok {
|
||||
@ -89,7 +91,12 @@ func CheckStruct(object interface{}, rules interface{}, msgs ...CustomMsg) *Erro
|
||||
}
|
||||
// 校验规则
|
||||
if _, ok := checkRules[name]; !ok {
|
||||
checkRules[name] = rule
|
||||
if _, ok := checkRules[fieldName]; ok {
|
||||
checkRules[name] = checkRules[fieldName]
|
||||
delete(checkRules, fieldName)
|
||||
} else {
|
||||
checkRules[name] = rule
|
||||
}
|
||||
errorRules = append(errorRules, name+"@"+rule)
|
||||
} else {
|
||||
// 传递的rules规则会覆盖struct tag的规则
|
||||
@ -116,11 +123,16 @@ func CheckStruct(object interface{}, rules interface{}, msgs ...CustomMsg) *Erro
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 自定义错误消息,非必须参数,优先级比rules参数中以及struct tag中定义的错误消息更高
|
||||
if len(msgs) > 0 && len(msgs[0]) > 0 {
|
||||
if len(customMsgs) > 0 {
|
||||
for k, v := range msgs[0] {
|
||||
customMsgs[k] = v
|
||||
if cmane, ok := cname[k]; ok {
|
||||
customMsgs[cmane] = v
|
||||
} else {
|
||||
customMsgs[k] = v
|
||||
}
|
||||
}
|
||||
} else {
|
||||
customMsgs = msgs[0]
|
||||
@ -136,6 +148,8 @@ func CheckStruct(object interface{}, rules interface{}, msgs ...CustomMsg) *Erro
|
||||
value = nil
|
||||
if v, ok := params[key]; ok {
|
||||
value = v
|
||||
} else { // 不存在的字段的规则跳过。例如rules使用[]string格式输入时,没有对应字段便会出现这种情况。
|
||||
continue
|
||||
}
|
||||
if e := Check(value, rule, customMsgs[key], params); e != nil {
|
||||
_, item := e.FirstItem()
|
||||
|
||||
64
g/util/gvalid/gvalid_unit_basic_array_slice_test.go
Normal file
64
g/util/gvalid/gvalid_unit_basic_array_slice_test.go
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gvalid_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"github.com/gogf/gf/g/util/gvalid"
|
||||
)
|
||||
|
||||
func Test_Array(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
arrayData := [2]int{7, 8}
|
||||
msgs := map[string]string{
|
||||
"between": "not between",
|
||||
"in": "not in",
|
||||
}
|
||||
|
||||
err := gvalid.Check(arrayData, "between:6,10|in:7,8", msgs)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
if e := gvalid.Check(arrayData, "between:9,10|in:7,8", msgs); e != nil {
|
||||
gtest.Assert(e.String(), "not between")
|
||||
}
|
||||
|
||||
if e := gvalid.Check(arrayData, "between:6,10|in:7", msgs); e != nil {
|
||||
gtest.Assert(e.String(), "not in")
|
||||
}
|
||||
|
||||
err1 := gvalid.Check(&arrayData, "between:6,10|in:7,8", msgs)
|
||||
gtest.Assert(err1, nil)
|
||||
|
||||
if e := gvalid.Check(&arrayData, "between:9,10|in:7,8", msgs); e != nil {
|
||||
gtest.Assert(e.String(), "not between")
|
||||
}
|
||||
|
||||
if e := gvalid.Check(&arrayData, "between:6,10|in:7", msgs); e != nil {
|
||||
gtest.Assert(e.String(), "not in")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Slice(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
sliceData := [][]string{[]string{"12345678", "12345678"}, []string{"12345678", "12345678"}}
|
||||
|
||||
msgs := map[string]string{
|
||||
"length": "length err",
|
||||
}
|
||||
|
||||
err := gvalid.Check(sliceData, "length:3,16", msgs)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
if e := gvalid.Check(sliceData, "length:9,16", msgs); e != nil {
|
||||
gtest.Assert(e.String(), "length err")
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
46
g/util/gvalid/gvalid_unit_basic_map_test.go
Normal file
46
g/util/gvalid/gvalid_unit_basic_map_test.go
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gvalid_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"github.com/gogf/gf/g/util/gvalid"
|
||||
)
|
||||
|
||||
func Test_Map(t *testing.T) {
|
||||
type Test struct {
|
||||
Id int
|
||||
}
|
||||
gtest.Case(t, func() {
|
||||
mapData := map[string]interface{}{
|
||||
"123": map[string]int{
|
||||
"aaa": 6,
|
||||
"bbb": 7,
|
||||
"ccc": 8,
|
||||
},
|
||||
"456": &Test{
|
||||
Id: 9,
|
||||
},
|
||||
}
|
||||
|
||||
err := gvalid.Check(mapData, "between:6,10|in:6,7,8,9", nil)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
msgs := map[string]string{
|
||||
"between": "not between",
|
||||
"in": "not in",
|
||||
}
|
||||
if e := gvalid.Check(mapData, "between:10,10|in:6,7,8,9", msgs); e != nil {
|
||||
gtest.Assert(e.String(), "not between")
|
||||
}
|
||||
if e := gvalid.Check(mapData, "between:6,10|in:10", msgs); e != nil {
|
||||
gtest.Assert(e.String(), "not in")
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user