github.com/gogf/gf/v2@v2.7.4/util/gvalid/gvalid_validator.go (about) 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 7 package gvalid 8 9 import ( 10 "context" 11 "errors" 12 "reflect" 13 14 "github.com/gogf/gf/v2/i18n/gi18n" 15 "github.com/gogf/gf/v2/internal/reflection" 16 "github.com/gogf/gf/v2/internal/utils" 17 "github.com/gogf/gf/v2/text/gstr" 18 "github.com/gogf/gf/v2/util/gconv" 19 ) 20 21 // Validator is the validation manager for chaining operations. 22 type Validator struct { 23 i18nManager *gi18n.Manager // I18n manager for error message translation. 24 data interface{} // Validation data, which can be a map, struct or a certain value to be validated. 25 assoc interface{} // Associated data, which is usually a map, for union validation. 26 rules interface{} // Custom validation data. 27 messages interface{} // Custom validation error messages, which can be string or type of CustomMsg. 28 ruleFuncMap map[string]RuleFunc // ruleFuncMap stores custom rule functions for current Validator. 29 useAssocInsteadOfObjectAttributes bool // Using `assoc` as its validation source instead of attribute values from `Object`. 30 bail bool // Stop validation after the first validation error. 31 foreach bool // It tells the next validation using current value as an array and validates each of its element. 32 caseInsensitive bool // Case-Insensitive configuration for those rules that need value comparison. 33 } 34 35 // New creates and returns a new Validator. 36 func New() *Validator { 37 return &Validator{ 38 i18nManager: gi18n.Instance(), // Use default i18n manager. 39 ruleFuncMap: make(map[string]RuleFunc), // Custom rule function storing map. 40 } 41 } 42 43 // Run starts validating the given data with rules and messages. 44 func (v *Validator) Run(ctx context.Context) Error { 45 if v.data == nil { 46 return newValidationErrorByStr( 47 internalParamsErrRuleName, 48 errors.New(`no data passed for validation`), 49 ) 50 } 51 52 originValueAndKind := reflection.OriginValueAndKind(v.data) 53 switch originValueAndKind.OriginKind { 54 case reflect.Map: 55 isMapValidation := false 56 if v.rules == nil { 57 isMapValidation = true 58 } else if utils.IsMap(v.rules) || utils.IsSlice(v.rules) { 59 isMapValidation = true 60 } 61 if isMapValidation { 62 return v.doCheckMap(ctx, v.data) 63 } 64 65 case reflect.Struct: 66 isStructValidation := false 67 if v.rules == nil { 68 isStructValidation = true 69 } else if utils.IsMap(v.rules) || utils.IsSlice(v.rules) { 70 isStructValidation = true 71 } 72 if isStructValidation { 73 return v.doCheckStruct(ctx, v.data) 74 } 75 } 76 77 return v.doCheckValue(ctx, doCheckValueInput{ 78 Name: "", 79 Value: v.data, 80 ValueType: reflect.TypeOf(v.data), 81 Rule: gconv.String(v.rules), 82 Messages: v.messages, 83 DataRaw: v.assoc, 84 DataMap: gconv.Map(v.assoc), 85 }) 86 } 87 88 // Clone creates and returns a new Validator which is a shallow copy of current one. 89 func (v *Validator) Clone() *Validator { 90 newValidator := New() 91 *newValidator = *v 92 return newValidator 93 } 94 95 // I18n sets the i18n manager for the validator. 96 func (v *Validator) I18n(i18nManager *gi18n.Manager) *Validator { 97 if i18nManager == nil { 98 return v 99 } 100 newValidator := v.Clone() 101 newValidator.i18nManager = i18nManager 102 return newValidator 103 } 104 105 // Bail sets the mark for stopping validation after the first validation error. 106 func (v *Validator) Bail() *Validator { 107 newValidator := v.Clone() 108 newValidator.bail = true 109 return newValidator 110 } 111 112 // Foreach tells the next validation using current value as an array and validates each of its element. 113 // Note that this decorating rule takes effect just once for next validation rule, specially for single value validation. 114 func (v *Validator) Foreach() *Validator { 115 newValidator := v.Clone() 116 newValidator.foreach = true 117 return newValidator 118 } 119 120 // Ci sets the mark for Case-Insensitive for those rules that need value comparison. 121 func (v *Validator) Ci() *Validator { 122 newValidator := v.Clone() 123 newValidator.caseInsensitive = true 124 return newValidator 125 } 126 127 // Data is a chaining operation function, which sets validation data for current operation. 128 func (v *Validator) Data(data interface{}) *Validator { 129 if data == nil { 130 return v 131 } 132 newValidator := v.Clone() 133 newValidator.data = data 134 return newValidator 135 } 136 137 // Assoc is a chaining operation function, which sets associated validation data for current operation. 138 // The optional parameter `assoc` is usually type of map, which specifies the parameter map used in union validation. 139 // Calling this function with `assoc` also sets `useAssocInsteadOfObjectAttributes` true 140 func (v *Validator) Assoc(assoc interface{}) *Validator { 141 if assoc == nil { 142 return v 143 } 144 newValidator := v.Clone() 145 newValidator.assoc = assoc 146 newValidator.useAssocInsteadOfObjectAttributes = true 147 return newValidator 148 } 149 150 // Rules is a chaining operation function, which sets custom validation rules for current operation. 151 func (v *Validator) Rules(rules interface{}) *Validator { 152 if rules == nil { 153 return v 154 } 155 newValidator := v.Clone() 156 newValidator.rules = rules 157 return newValidator 158 } 159 160 // Messages is a chaining operation function, which sets custom error messages for current operation. 161 // The parameter `messages` can be type of string/[]string/map[string]string. It supports sequence in error result 162 // if `rules` is type of []string. 163 func (v *Validator) Messages(messages interface{}) *Validator { 164 if messages == nil { 165 return v 166 } 167 newValidator := v.Clone() 168 newValidator.messages = messages 169 return newValidator 170 } 171 172 // RuleFunc registers one custom rule function to current Validator. 173 func (v *Validator) RuleFunc(rule string, f RuleFunc) *Validator { 174 newValidator := v.Clone() 175 newValidator.ruleFuncMap[rule] = f 176 return newValidator 177 } 178 179 // RuleFuncMap registers multiple custom rule functions to current Validator. 180 func (v *Validator) RuleFuncMap(m map[string]RuleFunc) *Validator { 181 if m == nil { 182 return v 183 } 184 newValidator := v.Clone() 185 for k, v := range m { 186 newValidator.ruleFuncMap[k] = v 187 } 188 return newValidator 189 } 190 191 // getCustomRuleFunc retrieves and returns the custom rule function for specified rule. 192 func (v *Validator) getCustomRuleFunc(rule string) RuleFunc { 193 ruleFunc := v.ruleFuncMap[rule] 194 if ruleFunc == nil { 195 ruleFunc = customRuleFuncMap[rule] 196 } 197 return ruleFunc 198 } 199 200 // checkRuleRequired checks and returns whether the given `rule` is required even it is nil or empty. 201 func (v *Validator) checkRuleRequired(rule string) bool { 202 // Default required rules. 203 if gstr.HasPrefix(rule, requiredRulesPrefix) { 204 return true 205 } 206 // All custom validation rules are required rules. 207 if _, ok := customRuleFuncMap[rule]; ok { 208 return true 209 } 210 return false 211 }