Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] When customizing validation rules, is it possible to return the corresponding binding structure or map, or even their reflection objects? ? ? #2891

Closed
shuqingzai opened this issue Aug 22, 2023 · 7 comments

Comments

@shuqingzai
Copy link

shuqingzai commented Aug 22, 2023

目前自定义规则中入参为:

type RuleFuncInput struct {
只有一个 Field 字段,在做通用性规则时,没法获取原来的 struct ,受限性挺大的

比如:我定义一个枚举类型,我只想传入的值在枚举值的一部分范围,而不是所有

// VailEnum 校验枚举值是否合法
type VailEnum interface {
	IsVailEnum() bool
}

type IEnum int

const (
	EnumUnknown IEnum = 0
	EnumEmail   IEnum = 1
	EnumName    IEnum = 2
)

func (e IEnum) IsVailEnum() bool {
	return e == EnumEmail || e == EnumName
}

需要实现的自定义大致规则如下:

// InEnums 检查 枚举类型 字段传入值是否在指定的枚举值中
//
// 字段类型必须实现 enums.VailEnum 接口
//
// Format: in-enums[#message]
type InEnums struct{}

func init() {
	rule := InEnums{}
	gvalid.RegisterRule(rule.Name(), rule.Run)
}

func (r InEnums) Name() string {
	return "in-enums"
}

func (r InEnums) Message() string {
	return "The {field} value `{value}` is not in the specified enum"
}

func (r InEnums) Run(ctx context.Context, in gvalid.RuleFuncInput) error {
	//  1. 反射获取原结构体类型
	objType := reflect.TypeOf(in.OrgType.Val())

       //  2. 遍历匹配 in.Field

	//  3. 判断是否实现了 enums.VailEnum 接口
	if objType.Implements(reflects.TypeOf((*enums.VailEnum)(nil)).Elem()) {
		// 4. 调用 VailEnum 接口的 IsVailEnum 方法验证
	}

	return nil
}

允许用户可以操作绑定的结构体或 map (可能新增的字段 in.OrgType ),让 Field 发挥他的价值,用户自定义规则更加自由

1. What version of Go and system type/arch are you using?

#-> % go version
go version go1.21.0 darwin/amd64

2. What version of GoFrame are you using?

#-> % gf version
GoFrame CLI Tool v2.5.1, https://goframe.org
GoFrame Version: v2.5.1 in current go.mod
CLI Installed At: /Code/go/bin/gf
CLI Built Detail:
  Go Version:  go1.20.4
  GF Version:  v2.5.1
  Git Commit:  2023-07-26 21:27:58 e0e00434cc87d6edf64fc3df40ce7d3f40758794
  Build Time:  2023-07-26 21:32:56

3. Can this issue be re-produced with the latest release?

是的

4. What did you do?

5. What did you expect to see?

6. What did you see instead?

@Issues-translate-bot Issues-translate-bot changed the title [Feature] 自定义验证规则时,是否可以返回对应绑定的结构体或 map ,甚至他们的反射对象??? [Feature] When customizing validation rules, is it possible to return the corresponding binding structure or map, or even their reflection objects? ? ? Aug 22, 2023
@gqcn
Copy link
Member

gqcn commented Aug 23, 2023

@shuqingzai 你检查一下这个输入参数是不是你想要的。另外,enums校验规则已经有了,不过需要结合gen enums命令一起使用。
image

@gqcn gqcn added the question label Aug 23, 2023
@hailaz
Copy link
Member

hailaz commented Aug 24, 2023

_, foundValue = gutil.MapPossibleItemByKey(in.Data.Map(), array[i])

可以参考内置的规则实现。

@Issues-translate-bot
Copy link

Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑‍🤝‍🧑👫🧑🏿‍🤝‍🧑🏻👩🏾‍🤝‍👨🏿👬🏿


_, foundValue = gutil.MapPossibleItemByKey(in.Data.Map(), array[i])

You can refer to the built-in rule implementation.

@shuqingzai
Copy link
Author

shuqingzai commented Aug 24, 2023

@shuqingzai 你检查一下这个输入参数是不是你想要的。另外,enums校验规则已经有了,不过需要结合gen enums命令一起使用。 image

@gqcn

  1. 这里拿到的是 map
    image
  2. enums 的问题也是,这里也拿到 map [BUG] Validation rules using enums are invalid #2890 (comment)

@shuqingzai
Copy link
Author

_, foundValue = gutil.MapPossibleItemByKey(in.Data.Map(), array[i])

可以参考内置的规则实现。

抱歉,我没能理解你的意思 @hailaz

@hailaz
Copy link
Member

hailaz commented Aug 29, 2023

_, foundValue = gutil.MapPossibleItemByKey(in.Data.Map(), array[i])

可以参考内置的规则实现。

抱歉,我没能理解你的意思 @hailaz

@shuqingzai 大概写了个示例,不算特别完善,也不代表最优解。只提供思路

// VailEnum 校验枚举值是否合法
type VailEnum interface {
	IsVailEnum() bool
}

type IEnum int

const (
	EnumUnknown IEnum = 0
	EnumEmail   IEnum = 1
	EnumName    IEnum = 2
)

func (e IEnum) IsVailEnum() bool {
	fmt.Println("IsVailEnum")
	return e == EnumEmail || e == EnumName
}

// TestMyEmnus description
//
// createTime: 2023-08-29 15:58:10
//
// author: hailaz
func TestMyEmnus(t *testing.T) {
	rule := "in-enums"
	gvalid.RegisterRule(
		rule,
		func(ctx context.Context, in gvalid.RuleFuncInput) error {
			// typeName := reflect.TypeOf(in.Data.Val())
			// fmt.Println("Type name:", typeName.Name(), in.Field)

			// TODO:输入的可能不是结构体
			// 获取输入的结构体的所有字段
			fields, _ := gstructs.Fields(gstructs.FieldsInput{
				Pointer:         in.Data.Val(),
				RecursiveOption: 0,
			})
			// 找到对应的字段进行判断
			for _, v := range fields {
				fmt.Println("Field name:", v.Field.Name)
				if v.Field.Name == in.Field {
					// 获取字段类型
					t := v.Value.Type()
					// 判断是否实现了接口
					if t.Implements(reflect.TypeOf((*VailEnum)(nil)).Elem()) {
						fmt.Println("实现了接口")
						// 执行接口方法
						res := v.Value.MethodByName("IsVailEnum").Call(nil)
						if res[0].Bool() {
							return nil
						} else {
							return errors.New(in.Message)
						}
					}
				}
			}

			return nil
		},
	)

	gtest.C(t, func(t *gtest.T) {
		type Test struct {
			UserType IEnum `v:"in-enums#值不正确"`
		}
		st := Test{
			UserType: 0,
		}
		err := g.Validator().Data(st).Run(ctx)
		t.AssertNil(err)
	})
}

@shuqingzai
Copy link
Author

shuqingzai commented Aug 30, 2023

@hailaz 谢谢你的回复,我觉得你的方法是可行,但是如果 #2890 (comment) 得到解决,我可以直接获取原始的数据结构与数据内容

使用 @gqcn 提供的方法

@shuqingzai 你检查一下这个输入参数是不是你想要的。另外,enums校验规则已经有了,不过需要结合gen enums命令一起使用。 image

@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Oct 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants