From 5929698c9b744316fa09b2172c19259ba01c5ab9 Mon Sep 17 00:00:00 2001 From: John Guo Date: Sun, 4 Feb 2024 17:02:22 +0800 Subject: [PATCH] fix issue #2503 --- util/gvalid/gvalid_validator_check_struct.go | 3 +- util/gvalid/gvalid_validator_check_value.go | 2 +- util/gvalid/gvalid_z_unit_issue_test.go | 36 +++++++++++++++++++ .../internal/builtin/builtin_required.go | 2 ++ 4 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 util/gvalid/gvalid_z_unit_issue_test.go diff --git a/util/gvalid/gvalid_validator_check_struct.go b/util/gvalid/gvalid_validator_check_struct.go index 8a96f64546d..129dafbc37a 100644 --- a/util/gvalid/gvalid_validator_check_struct.go +++ b/util/gvalid/gvalid_validator_check_struct.go @@ -239,6 +239,7 @@ func (v *Validator) doCheckStruct(ctx context.Context, object interface{}) Error continue } if field.IsEmbedded() { + // The attributes of embedded struct are considered as direct attributes of its parent struct. if err = v.doCheckStruct(ctx, field.Value); err != nil { // It merges the errors into single error map. for k, m := range err.(*validationError).errors { @@ -257,7 +258,7 @@ func (v *Validator) doCheckStruct(ctx context.Context, object interface{}) Error value = getPossibleValueFromMap( inputParamMap, field.Name(), fieldToAliasNameMap[field.Name()], ) - if value == nil { + if empty.IsNil(value) { switch field.Kind() { case reflect.Map, reflect.Ptr, reflect.Slice, reflect.Array: // Nothing to do. diff --git a/util/gvalid/gvalid_validator_check_value.go b/util/gvalid/gvalid_validator_check_value.go index dabd4a634fe..759e97239af 100644 --- a/util/gvalid/gvalid_validator_check_value.go +++ b/util/gvalid/gvalid_validator_check_value.go @@ -23,7 +23,7 @@ import ( ) type doCheckValueInput struct { - Name string // Name specifies the name of parameter `value`. + Name string // Name specifies the name of parameter `value`, which might be the custom tag name of the parameter. Value interface{} // Value specifies the value for the rules to be validated. ValueType reflect.Type // ValueType specifies the type of the value, mainly used for value type id retrieving. Rule string // Rule specifies the validation rules string, like "required", "required|between:1,100", etc. diff --git a/util/gvalid/gvalid_z_unit_issue_test.go b/util/gvalid/gvalid_z_unit_issue_test.go new file mode 100644 index 00000000000..d7520d99d53 --- /dev/null +++ b/util/gvalid/gvalid_z_unit_issue_test.go @@ -0,0 +1,36 @@ +// Copyright GoFrame Author(https://goframe.org). 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 ( + "context" + "testing" + + "github.com/gogf/gf/v2/util/gvalid" +) + +type Foo struct { + Bar *Bar `p:"bar" v:"required-without:Baz"` + Baz *Baz `p:"baz" v:"required-without:Bar"` +} +type Bar struct { + BarKey string `p:"bar_key" v:"required"` +} +type Baz struct { + BazKey string `p:"baz_key" v:"required"` +} + +// https://github.com/gogf/gf/issues/2503 +func Test_Issue2503(t *testing.T) { + foo := &Foo{ + Bar: &Bar{BarKey: "value"}, + } + err := gvalid.New().Data(foo).Run(context.Background()) + if err != nil { + t.Fatal(err) + } +} diff --git a/util/gvalid/internal/builtin/builtin_required.go b/util/gvalid/internal/builtin/builtin_required.go index bf6133215da..a70293ebbcf 100644 --- a/util/gvalid/internal/builtin/builtin_required.go +++ b/util/gvalid/internal/builtin/builtin_required.go @@ -36,6 +36,8 @@ func (r RuleRequired) Run(in RunInput) error { return nil } +// isRequiredEmpty checks and returns whether given value is empty string. +// Note that if given value is a zero integer, it will be considered as not empty. func isRequiredEmpty(value interface{}) bool { reflectValue := reflect.ValueOf(value) for reflectValue.Kind() == reflect.Ptr {