github.com/wangyougui/gf/v2@v2.6.5/util/gvalid/gvalid_validator_check_map.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/wangyougui/gf. 6 7 package gvalid 8 9 import ( 10 "context" 11 "errors" 12 "reflect" 13 "strings" 14 15 "github.com/wangyougui/gf/v2/errors/gcode" 16 "github.com/wangyougui/gf/v2/internal/reflection" 17 "github.com/wangyougui/gf/v2/util/gconv" 18 ) 19 20 func (v *Validator) doCheckMap(ctx context.Context, params interface{}) Error { 21 if params == nil { 22 return nil 23 } 24 var ( 25 checkRules = make([]fieldRule, 0) 26 customMessage = make(CustomMsg) // map[RuleKey]ErrorMsg. 27 errorMaps = make(map[string]map[string]error) 28 ) 29 switch assertValue := v.rules.(type) { 30 // Sequence tag: []sequence tag 31 // Sequence has order for error results. 32 case []string: 33 for _, tag := range assertValue { 34 name, rule, msg := ParseTagValue(tag) 35 if len(name) == 0 { 36 continue 37 } 38 if len(msg) > 0 { 39 var ( 40 msgArray = strings.Split(msg, "|") 41 ruleArray = strings.Split(rule, "|") 42 ) 43 for k, ruleItem := range ruleArray { 44 // If length of custom messages is lesser than length of rules, 45 // the rest rules use the default error messages. 46 if len(msgArray) <= k { 47 continue 48 } 49 if len(msgArray[k]) == 0 { 50 continue 51 } 52 array := strings.Split(ruleItem, ":") 53 if _, ok := customMessage[name]; !ok { 54 customMessage[name] = make(map[string]string) 55 } 56 customMessage[name].(map[string]string)[strings.TrimSpace(array[0])] = strings.TrimSpace(msgArray[k]) 57 } 58 } 59 checkRules = append(checkRules, fieldRule{ 60 Name: name, 61 Rule: rule, 62 }) 63 } 64 65 // No sequence rules: map[field]rule 66 case map[string]string: 67 for name, rule := range assertValue { 68 checkRules = append(checkRules, fieldRule{ 69 Name: name, 70 Rule: rule, 71 }) 72 } 73 } 74 inputParamMap := gconv.Map(params) 75 if inputParamMap == nil { 76 return newValidationErrorByStr( 77 internalParamsErrRuleName, 78 errors.New("invalid params type: convert to map failed"), 79 ) 80 } 81 if msg, ok := v.messages.(CustomMsg); ok && len(msg) > 0 { 82 if len(customMessage) > 0 { 83 for k, v := range msg { 84 customMessage[k] = v 85 } 86 } else { 87 customMessage = msg 88 } 89 } 90 var ( 91 value interface{} 92 validator = v.Clone() 93 ) 94 95 // It checks the struct recursively if its attribute is an embedded struct. 96 // Ignore inputParamMap, assoc, rules and messages from parent. 97 validator.assoc = nil 98 validator.rules = nil 99 validator.messages = nil 100 for _, item := range inputParamMap { 101 originTypeAndKind := reflection.OriginTypeAndKind(item) 102 switch originTypeAndKind.OriginKind { 103 case reflect.Map, reflect.Struct, reflect.Slice, reflect.Array: 104 v.doCheckValueRecursively(ctx, doCheckValueRecursivelyInput{ 105 Value: item, 106 Type: originTypeAndKind.InputType, 107 Kind: originTypeAndKind.OriginKind, 108 ErrorMaps: errorMaps, 109 }) 110 } 111 // Bail feature. 112 if v.bail && len(errorMaps) > 0 { 113 break 114 } 115 } 116 if v.bail && len(errorMaps) > 0 { 117 return newValidationError(gcode.CodeValidationFailed, nil, errorMaps) 118 } 119 120 // The following logic is the same as some of CheckStruct but without sequence support. 121 for _, checkRuleItem := range checkRules { 122 if len(checkRuleItem.Rule) == 0 { 123 continue 124 } 125 value = nil 126 if valueItem, ok := inputParamMap[checkRuleItem.Name]; ok { 127 value = valueItem 128 } 129 // It checks each rule and its value in loop. 130 if validatedError := v.doCheckValue(ctx, doCheckValueInput{ 131 Name: checkRuleItem.Name, 132 Value: value, 133 ValueType: reflect.TypeOf(value), 134 Rule: checkRuleItem.Rule, 135 Messages: customMessage[checkRuleItem.Name], 136 DataRaw: params, 137 DataMap: inputParamMap, 138 }); validatedError != nil { 139 _, errorItem := validatedError.FirstItem() 140 // =========================================================== 141 // Only in map and struct validations: 142 // If value is nil or empty string and has no required* rules, 143 // it clears the error message. 144 // =========================================================== 145 if gconv.String(value) == "" { 146 required := false 147 // rule => error 148 for ruleKey := range errorItem { 149 if required = v.checkRuleRequired(ruleKey); required { 150 break 151 } 152 } 153 if !required { 154 continue 155 } 156 } 157 if _, ok := errorMaps[checkRuleItem.Name]; !ok { 158 errorMaps[checkRuleItem.Name] = make(map[string]error) 159 } 160 for ruleKey, ruleError := range errorItem { 161 errorMaps[checkRuleItem.Name][ruleKey] = ruleError 162 } 163 if v.bail { 164 break 165 } 166 } 167 } 168 if len(errorMaps) > 0 { 169 return newValidationError(gcode.CodeValidationFailed, checkRules, errorMaps) 170 } 171 return nil 172 }