gvalid.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
  2. //
  3. // This Source Code Form is subject to the terms of the MIT License.
  4. // If a copy of the MIT was not distributed with this file,
  5. // You can obtain one at https://github.com/gogf/gf.
  6. // Package gvalid implements powerful and useful data/form validation functionality.
  7. package gvalid
  8. import (
  9. "context"
  10. "reflect"
  11. "regexp"
  12. "strings"
  13. "github.com/gogf/gf/v2/internal/intlog"
  14. "github.com/gogf/gf/v2/text/gregex"
  15. )
  16. // CustomMsg is the custom error message type,
  17. // like: map[field] => string|map[rule]string
  18. type CustomMsg = map[string]interface{}
  19. // fieldRule defined the alias name and rule string for specified field.
  20. type fieldRule struct {
  21. Name string // Alias name for the field.
  22. Rule string // Rule string like: "max:6"
  23. IsMeta bool // Is this rule is from gmeta.Meta, which marks it as whole struct rule.
  24. FieldKind reflect.Kind // Kind of struct field, which is used for parameter type checks.
  25. }
  26. // iNoValidation is an interface that marks current struct not validated by package `gvalid`.
  27. type iNoValidation interface {
  28. NoValidation()
  29. }
  30. const (
  31. singleRulePattern = `^([\w-]+):{0,1}(.*)` // regular expression pattern for single validation rule.
  32. internalRulesErrRuleName = "InvalidRules" // rule name for internal invalid rules validation error.
  33. internalParamsErrRuleName = "InvalidParams" // rule name for internal invalid params validation error.
  34. internalObjectErrRuleName = "InvalidObject" // rule name for internal invalid object validation error.
  35. internalErrorMapKey = "__InternalError__" // error map key for internal errors.
  36. internalDefaultRuleName = "__default__" // default rule name for i18n error message format if no i18n message found for specified error rule.
  37. ruleMessagePrefixForI18n = "gf.gvalid.rule." // prefix string for each rule configuration in i18n content.
  38. noValidationTagName = "nv" // no validation tag name for struct attribute.
  39. ruleNameRegex = "regex" // the name for rule "regex"
  40. ruleNameNotRegex = "not-regex" // the name for rule "not-regex"
  41. ruleNameForeach = "foreach" // the name for rule "foreach"
  42. ruleNameBail = "bail" // the name for rule "bail"
  43. ruleNameCi = "ci" // the name for rule "ci"
  44. emptyJsonArrayStr = "[]" // Empty json string for array type.
  45. emptyJsonObjectStr = "{}" // Empty json string for object type.
  46. requiredRulesPrefix = "required" // requiredRulesPrefix specifies the rule prefix that must be validated even the value is empty (nil or empty).
  47. )
  48. var (
  49. // defaultErrorMessages is the default error messages.
  50. // Note that these messages are synchronized from ./i18n/en/validation.toml .
  51. defaultErrorMessages = map[string]string{
  52. internalDefaultRuleName: "The {field} value `{value}` is invalid",
  53. }
  54. structTagPriority = []string{"gvalid", "valid", "v"} // structTagPriority specifies the validation tag priority array.
  55. aliasNameTagPriority = []string{"param", "params", "p"} // aliasNameTagPriority specifies the alias tag priority array.
  56. // all internal error keys.
  57. internalErrKeyMap = map[string]string{
  58. internalRulesErrRuleName: internalRulesErrRuleName,
  59. internalParamsErrRuleName: internalParamsErrRuleName,
  60. internalObjectErrRuleName: internalObjectErrRuleName,
  61. }
  62. // regular expression object for single rule
  63. // which is compiled just once and of repeatable usage.
  64. ruleRegex, _ = regexp.Compile(singleRulePattern)
  65. // decorativeRuleMap defines all rules that are just marked rules which have neither functional meaning
  66. // nor error messages.
  67. decorativeRuleMap = map[string]bool{
  68. ruleNameForeach: true,
  69. ruleNameBail: true,
  70. ruleNameCi: true,
  71. }
  72. )
  73. // ParseTagValue parses one sequence tag to field, rule and error message.
  74. // The sequence tag is like: [alias@]rule[...#msg...]
  75. func ParseTagValue(tag string) (field, rule, msg string) {
  76. // Complete sequence tag.
  77. // Example: name@required|length:2,20|password3|same:password1#||密码强度不足|两次密码不一致
  78. match, _ := gregex.MatchString(`\s*((\w+)\s*@){0,1}\s*([^#]+)\s*(#\s*(.*)){0,1}\s*`, tag)
  79. if len(match) > 5 {
  80. msg = strings.TrimSpace(match[5])
  81. rule = strings.TrimSpace(match[3])
  82. field = strings.TrimSpace(match[2])
  83. } else {
  84. intlog.Errorf(context.TODO(), `invalid validation tag value: %s`, tag)
  85. }
  86. return
  87. }
  88. // GetTags returns the validation tags.
  89. func GetTags() []string {
  90. return structTagPriority
  91. }