mirror of
https://gitee.com/johng/gf.git
synced 2024-11-30 03:07:45 +08:00
improve package gvalid for custom rule
This commit is contained in:
parent
1671391195
commit
a29aef7e1c
@ -124,9 +124,9 @@ func doCheck(key string, value interface{}, rules string, messages interface{},
|
||||
// It converts value to string and then does the validation.
|
||||
var (
|
||||
// Do not trim it as the space is also part of the value.
|
||||
val = gconv.String(value)
|
||||
data = make(map[string]string)
|
||||
errorMsgs = make(map[string]string)
|
||||
val = gconv.String(value)
|
||||
data = make(map[string]string)
|
||||
errorMsgArray = make(map[string]string)
|
||||
)
|
||||
if len(params) > 0 {
|
||||
for k, v := range gconv.Map(params[0]) {
|
||||
@ -198,7 +198,7 @@ func doCheck(key string, value interface{}, rules string, messages interface{},
|
||||
"min-length",
|
||||
"max-length":
|
||||
if msg := checkLength(val, ruleKey, ruleVal, customMsgMap); msg != "" {
|
||||
errorMsgs[ruleKey] = msg
|
||||
errorMsgArray[ruleKey] = msg
|
||||
} else {
|
||||
match = true
|
||||
}
|
||||
@ -209,7 +209,7 @@ func doCheck(key string, value interface{}, rules string, messages interface{},
|
||||
"max",
|
||||
"between":
|
||||
if msg := checkRange(val, ruleKey, ruleVal, customMsgMap); msg != "" {
|
||||
errorMsgs[ruleKey] = msg
|
||||
errorMsgArray[ruleKey] = msg
|
||||
} else {
|
||||
match = true
|
||||
}
|
||||
@ -246,7 +246,7 @@ func doCheck(key string, value interface{}, rules string, messages interface{},
|
||||
var msg string
|
||||
msg = getErrorMessageByRule(ruleKey, customMsgMap)
|
||||
msg = strings.Replace(msg, ":format", ruleVal, -1)
|
||||
errorMsgs[ruleKey] = msg
|
||||
errorMsgArray[ruleKey] = msg
|
||||
}
|
||||
|
||||
// Values of two fields should be equal as string.
|
||||
@ -260,7 +260,7 @@ func doCheck(key string, value interface{}, rules string, messages interface{},
|
||||
var msg string
|
||||
msg = getErrorMessageByRule(ruleKey, customMsgMap)
|
||||
msg = strings.Replace(msg, ":field", ruleVal, -1)
|
||||
errorMsgs[ruleKey] = msg
|
||||
errorMsgArray[ruleKey] = msg
|
||||
}
|
||||
|
||||
// Values of two fields should not be equal as string.
|
||||
@ -275,7 +275,7 @@ func doCheck(key string, value interface{}, rules string, messages interface{},
|
||||
var msg string
|
||||
msg = getErrorMessageByRule(ruleKey, customMsgMap)
|
||||
msg = strings.Replace(msg, ":field", ruleVal, -1)
|
||||
errorMsgs[ruleKey] = msg
|
||||
errorMsgArray[ruleKey] = msg
|
||||
}
|
||||
|
||||
// Field value should be in range of.
|
||||
@ -451,6 +451,7 @@ func doCheck(key string, value interface{}, rules string, messages interface{},
|
||||
match = gregex.IsMatchString(`^([0-9A-Fa-f]{2}[\-:]){5}[0-9A-Fa-f]{2}$`, val)
|
||||
|
||||
default:
|
||||
// Custom validation rules.
|
||||
if f, ok := customRuleFuncMap[ruleKey]; ok {
|
||||
var (
|
||||
dataMap map[string]interface{}
|
||||
@ -461,12 +462,12 @@ func doCheck(key string, value interface{}, rules string, messages interface{},
|
||||
}
|
||||
if err := f(value, message, dataMap); err != nil {
|
||||
match = false
|
||||
errorMsgs[ruleKey] = err.Error()
|
||||
errorMsgArray[ruleKey] = err.Error()
|
||||
} else {
|
||||
match = true
|
||||
}
|
||||
} else {
|
||||
errorMsgs[ruleKey] = "Invalid rule name: " + ruleKey
|
||||
errorMsgArray[ruleKey] = "Invalid rule name: " + ruleKey
|
||||
}
|
||||
}
|
||||
|
||||
@ -474,15 +475,15 @@ func doCheck(key string, value interface{}, rules string, messages interface{},
|
||||
if !match {
|
||||
// It does nothing if the error message for this rule
|
||||
// is already set in previous validation.
|
||||
if _, ok := errorMsgs[ruleKey]; !ok {
|
||||
errorMsgs[ruleKey] = getErrorMessageByRule(ruleKey, customMsgMap)
|
||||
if _, ok := errorMsgArray[ruleKey]; !ok {
|
||||
errorMsgArray[ruleKey] = getErrorMessageByRule(ruleKey, customMsgMap)
|
||||
}
|
||||
}
|
||||
index++
|
||||
}
|
||||
if len(errorMsgs) > 0 {
|
||||
if len(errorMsgArray) > 0 {
|
||||
return newError([]string{rules}, ErrorMap{
|
||||
key: errorMsgs,
|
||||
key: errorMsgArray,
|
||||
})
|
||||
}
|
||||
return nil
|
||||
|
@ -13,7 +13,8 @@ import (
|
||||
// RuleFunc is the custom function for data validation.
|
||||
// The parameter <value> specifies the value for this rule to validate.
|
||||
// The parameter <message> specifies the custom error message or configured i18n message for this rule.
|
||||
// The parameter <params> specifies all the parameters that needs .
|
||||
// The parameter <params> specifies all the parameters that needs. You can ignore parameter <params> if
|
||||
// you do not really need it in your custom validation rule.
|
||||
type RuleFunc func(value interface{}, message string, params map[string]interface{}) error
|
||||
|
||||
var (
|
||||
|
@ -49,17 +49,26 @@ func newErrorStr(key, err string) *Error {
|
||||
|
||||
// Map returns the first error message as map.
|
||||
func (e *Error) Map() map[string]string {
|
||||
if e == nil {
|
||||
return map[string]string{}
|
||||
}
|
||||
_, m := e.FirstItem()
|
||||
return m
|
||||
}
|
||||
|
||||
// Maps returns all error messages as map.
|
||||
func (e *Error) Maps() ErrorMap {
|
||||
if e == nil {
|
||||
return nil
|
||||
}
|
||||
return e.errors
|
||||
}
|
||||
|
||||
// FirstItem returns the field name and error messages for the first validation rule error.
|
||||
func (e *Error) FirstItem() (key string, messages map[string]string) {
|
||||
if e == nil {
|
||||
return "", map[string]string{}
|
||||
}
|
||||
if e.firstItem != nil {
|
||||
return e.firstKey, e.firstItem
|
||||
}
|
||||
@ -85,6 +94,9 @@ func (e *Error) FirstItem() (key string, messages map[string]string) {
|
||||
|
||||
// FirstRule returns the first error rule and message string.
|
||||
func (e *Error) FirstRule() (rule string, err string) {
|
||||
if e == nil {
|
||||
return "", ""
|
||||
}
|
||||
// By sequence.
|
||||
if len(e.rules) > 0 {
|
||||
for _, v := range e.rules {
|
||||
@ -112,22 +124,34 @@ func (e *Error) FirstRule() (rule string, err string) {
|
||||
// FirstString returns the first error message as string.
|
||||
// Note that the returned message might be different if it has no sequence.
|
||||
func (e *Error) FirstString() (err string) {
|
||||
if e == nil {
|
||||
return ""
|
||||
}
|
||||
_, err = e.FirstRule()
|
||||
return
|
||||
}
|
||||
|
||||
// String returns all error messages as string, multiple error messages joined using char ';'.
|
||||
func (e *Error) String() string {
|
||||
if e == nil {
|
||||
return ""
|
||||
}
|
||||
return strings.Join(e.Strings(), "; ")
|
||||
}
|
||||
|
||||
// Error implements interface of error.Error.
|
||||
func (e *Error) Error() string {
|
||||
if e == nil {
|
||||
return ""
|
||||
}
|
||||
return e.String()
|
||||
}
|
||||
|
||||
// Strings returns all error messages as string array.
|
||||
func (e *Error) Strings() (errs []string) {
|
||||
if e == nil {
|
||||
return []string{}
|
||||
}
|
||||
errs = make([]string, 0)
|
||||
// By sequence.
|
||||
if len(e.rules) > 0 {
|
||||
|
@ -57,6 +57,7 @@ var defaultMessages = map[string]string{
|
||||
"in": "The :attribute value is not in acceptable range",
|
||||
"not-in": "The :attribute value is not in acceptable range",
|
||||
"regex": "The :attribute value is invalid",
|
||||
"__default__": "The :attribute value is invalid",
|
||||
}
|
||||
|
||||
// getErrorMessageByRule retrieves and returns the error message for specified rule.
|
||||
@ -71,5 +72,12 @@ func getErrorMessageByRule(ruleKey string, customMsgMap map[string]string) strin
|
||||
if content == "" {
|
||||
content = defaultMessages[ruleKey]
|
||||
}
|
||||
// If there's no configured rule message, it uses default one.
|
||||
if content == "" {
|
||||
content = gi18n.GetContent(`gf.gvalid.rule.__default__`)
|
||||
if content == "" {
|
||||
content = defaultMessages["__default__"]
|
||||
}
|
||||
}
|
||||
return content
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ import (
|
||||
"github.com/gogf/gf/util/gvalid"
|
||||
)
|
||||
|
||||
func Test_CustomRule(t *testing.T) {
|
||||
func Test_CustomRule1(t *testing.T) {
|
||||
rule := "custom"
|
||||
err := gvalid.RegisterRule(rule, func(value interface{}, message string, params map[string]interface{}) error {
|
||||
pass := gconv.String(value)
|
||||
@ -62,3 +62,47 @@ func Test_CustomRule(t *testing.T) {
|
||||
t.Assert(err, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_CustomRule2(t *testing.T) {
|
||||
rule := "required-map"
|
||||
err := gvalid.RegisterRule(rule, func(value interface{}, message string, params map[string]interface{}) error {
|
||||
m := gconv.Map(value)
|
||||
if len(m) == 0 {
|
||||
return errors.New(message)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
gtest.Assert(err, nil)
|
||||
// Check.
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
errStr := "data map should not be empty"
|
||||
t.Assert(gvalid.Check(g.Map{}, rule, errStr).String(), errStr)
|
||||
t.Assert(gvalid.Check(g.Map{"k": "v"}, rule, errStr).String(), nil)
|
||||
})
|
||||
// Error with struct validation.
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type T struct {
|
||||
Value map[string]string `v:"uid@required-map#自定义错误"`
|
||||
Data string `p:"data"`
|
||||
}
|
||||
st := &T{
|
||||
Value: map[string]string{},
|
||||
Data: "123456",
|
||||
}
|
||||
err := gvalid.CheckStruct(st, nil)
|
||||
t.Assert(err.String(), "自定义错误")
|
||||
})
|
||||
// No error with struct validation.
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type T struct {
|
||||
Value map[string]string `v:"uid@required-map#自定义错误"`
|
||||
Data string `p:"data"`
|
||||
}
|
||||
st := &T{
|
||||
Value: map[string]string{"k": "v"},
|
||||
Data: "123456",
|
||||
}
|
||||
err := gvalid.CheckStruct(st, nil)
|
||||
t.Assert(err, nil)
|
||||
})
|
||||
}
|
||||
|
@ -7,8 +7,11 @@
|
||||
package gvalid_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/container/gvar"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"github.com/gogf/gf/util/gvalid"
|
||||
)
|
||||
|
||||
@ -106,3 +109,35 @@ func ExampleCheckStruct3() {
|
||||
// Output:
|
||||
// project id must between 1, 10000
|
||||
}
|
||||
|
||||
func ExampleRegisterRule() {
|
||||
rule := "unique-name"
|
||||
gvalid.RegisterRule(rule, func(value interface{}, message string, params map[string]interface{}) error {
|
||||
var (
|
||||
id = gconv.Int(params["Id"])
|
||||
name = gconv.String(value)
|
||||
)
|
||||
n, err := g.Table("user").Where("id != ? and name = ?", id, name).Count()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n > 0 {
|
||||
return errors.New(message)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
type User struct {
|
||||
Id int
|
||||
Name string `v:"required|unique-name # 请输入用户名称|用户名称已被占用"`
|
||||
Pass string `v:"required|length:6,18"`
|
||||
}
|
||||
user := &User{
|
||||
Id: 1,
|
||||
Name: "john",
|
||||
Pass: "123456",
|
||||
}
|
||||
err := gvalid.CheckStruct(user, nil)
|
||||
fmt.Println(err.Error())
|
||||
// Output:
|
||||
// 用户名称已被占用
|
||||
}
|
||||
|
@ -40,4 +40,5 @@
|
||||
"gf.gvalid.rule.different" = ":attribute 字段值不能与:field相同"
|
||||
"gf.gvalid.rule.in" = ":attribute 字段值不合法"
|
||||
"gf.gvalid.rule.not-in" = ":attribute 字段值不合法"
|
||||
"gf.gvalid.rule.regex" = ":attribute 字段值不合法"
|
||||
"gf.gvalid.rule.regex" = ":attribute 字段值不合法"
|
||||
"gf.gvalid.rule.__default__" = ":attribute 字段值不合法"
|
@ -40,4 +40,5 @@
|
||||
"gf.gvalid.rule.different" = "The :attribute value must be different from field :field"
|
||||
"gf.gvalid.rule.in" = "The :attribute value is not in acceptable range"
|
||||
"gf.gvalid.rule.not-in" = "The :attribute value is not in acceptable range"
|
||||
"gf.gvalid.rule.regex" = "The :attribute value is invalid"
|
||||
"gf.gvalid.rule.regex" = "The :attribute value is invalid"
|
||||
"gf.gvalid.rule.__default__" = "The :attribute value is invalid"
|
Loading…
Reference in New Issue
Block a user