diff --git a/validation/README.md b/validation/README.md index 5c3212b0..43373e47 100644 --- a/validation/README.md +++ b/validation/README.md @@ -64,6 +64,9 @@ Struct Tag Use: func main() { valid := validation.Validation{} + // ignore empty field valid + // see CanSkipFuncs + // valid := validation.Validation{RequiredFirst:true} u := user{Name: "test", Age: 40} b, err := valid.Valid(u) if err != nil { diff --git a/validation/validation.go b/validation/validation.go index 9dc51106..ef484fb3 100644 --- a/validation/validation.go +++ b/validation/validation.go @@ -106,6 +106,11 @@ func (r *Result) Message(message string, args ...interface{}) *Result { // A Validation context manages data validation and error messages. type Validation struct { + // if this field set true, in struct tag valid + // if the struct field vale is empty + // it will skip those valid functions, see CanSkipFuncs + RequiredFirst bool + Errors []*Error ErrorsMap map[string]*Error } @@ -324,7 +329,19 @@ func (v *Validation) Valid(obj interface{}) (b bool, err error) { if vfs, err = getValidFuncs(objT.Field(i)); err != nil { return } + + var hasReuired bool for _, vf := range vfs { + if vf.Name == "Required" { + hasReuired = true + } + + if !hasReuired && v.RequiredFirst && len(objV.Field(i).String()) == 0 { + if _, ok := CanSkipFuncs[vf.Name]; ok { + continue + } + } + if _, err = funcs.Call(vf.Name, mergeParam(v, objV.Field(i).Interface(), vf.Params)...); err != nil { return diff --git a/validation/validation_test.go b/validation/validation_test.go index 71a8bd17..bf612015 100644 --- a/validation/validation_test.go +++ b/validation/validation_test.go @@ -391,3 +391,54 @@ func TestRecursiveValid(t *testing.T) { t.Error("validation should not be passed") } } + +func TestSkipValid(t *testing.T) { + type User struct { + ID int + + Email string `valid:"Email"` + ReqEmail string `valid:"Required;Email"` + + IP string `valid:"IP"` + ReqIP string `valid:"Required;IP"` + + Mobile string `valid:"Mobile"` + ReqMobile string `valid:"Required;Mobile"` + + Tel string `valid:"Tel"` + ReqTel string `valid:"Required;Tel"` + + Phone string `valid:"Phone"` + ReqPhone string `valid:"Required;Phone"` + + ZipCode string `valid:"ZipCode"` + ReqZipCode string `valid:"Required;ZipCode"` + } + + u := User{ + ReqEmail: "a@a.com", + ReqIP: "127.0.0.1", + ReqMobile: "18888888888", + ReqTel: "02088888888", + ReqPhone: "02088888888", + ReqZipCode: "510000", + } + + valid := Validation{} + b, err := valid.Valid(u) + if err != nil { + t.Fatal(err) + } + if b { + t.Fatal("validation should not be passed") + } + + valid = Validation{RequiredFirst: true} + b, err = valid.Valid(u) + if err != nil { + t.Fatal(err) + } + if !b { + t.Fatal("validation should be passed") + } +} diff --git a/validation/validators.go b/validation/validators.go index 5248542a..a9c3e6b8 100644 --- a/validation/validators.go +++ b/validation/validators.go @@ -23,6 +23,16 @@ import ( "unicode/utf8" ) +// CanSkipFuncs will skip valid if RequiredFirst is true and the struct field's value is empty +var CanSkipFuncs = map[string]struct{}{ + "Email": struct{}{}, + "IP": struct{}{}, + "Mobile": struct{}{}, + "Tel": struct{}{}, + "Phone": struct{}{}, + "ZipCode": struct{}{}, +} + // MessageTmpls store commond validate template var MessageTmpls = map[string]string{ "Required": "Can not be empty",