github.com/gogf/gf@v1.16.9/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/gogf/gf.
     6  
     7  package gvalid
     8  
     9  import (
    10  	"github.com/gogf/gf/errors/gcode"
    11  	"github.com/gogf/gf/util/gconv"
    12  	"strings"
    13  )
    14  
    15  // CheckMap validates map and returns the error result. It returns nil if with successful validation.
    16  // The parameter `params` should be type of map.
    17  func (v *Validator) CheckMap(params interface{}) Error {
    18  	return v.doCheckMap(params)
    19  }
    20  
    21  func (v *Validator) doCheckMap(params interface{}) Error {
    22  	// If there's no validation rules, it does nothing and returns quickly.
    23  	if params == nil || v.rules == nil {
    24  		return nil
    25  	}
    26  	var (
    27  		checkRules    = make([]fieldRule, 0)
    28  		customMessage = make(CustomMsg) // map[RuleKey]ErrorMsg.
    29  		errorMaps     = make(map[string]map[string]string)
    30  	)
    31  	switch assertValue := v.rules.(type) {
    32  	// Sequence tag: []sequence tag
    33  	// Sequence has order for error results.
    34  	case []string:
    35  		for _, tag := range assertValue {
    36  			name, rule, msg := parseSequenceTag(tag)
    37  			if len(name) == 0 {
    38  				continue
    39  			}
    40  			if len(msg) > 0 {
    41  				var (
    42  					msgArray  = strings.Split(msg, "|")
    43  					ruleArray = strings.Split(rule, "|")
    44  				)
    45  				for k, ruleItem := range ruleArray {
    46  					// If length of custom messages is lesser than length of rules,
    47  					// the rest rules use the default error messages.
    48  					if len(msgArray) <= k {
    49  						continue
    50  					}
    51  					if len(msgArray[k]) == 0 {
    52  						continue
    53  					}
    54  					array := strings.Split(ruleItem, ":")
    55  					if _, ok := customMessage[name]; !ok {
    56  						customMessage[name] = make(map[string]string)
    57  					}
    58  					customMessage[name].(map[string]string)[strings.TrimSpace(array[0])] = strings.TrimSpace(msgArray[k])
    59  				}
    60  			}
    61  			checkRules = append(checkRules, fieldRule{
    62  				Name: name,
    63  				Rule: rule,
    64  			})
    65  		}
    66  
    67  	// No sequence rules: map[field]rule
    68  	case map[string]string:
    69  		for name, rule := range assertValue {
    70  			checkRules = append(checkRules, fieldRule{
    71  				Name: name,
    72  				Rule: rule,
    73  			})
    74  		}
    75  	}
    76  	// If there's no validation rules, it does nothing and returns quickly.
    77  	if len(checkRules) == 0 {
    78  		return nil
    79  	}
    80  	data := gconv.Map(params)
    81  	if data == nil {
    82  		return newErrorStr(
    83  			internalParamsErrRuleName,
    84  			"invalid params type: convert to map failed",
    85  		)
    86  	}
    87  	if msg, ok := v.messages.(CustomMsg); ok && len(msg) > 0 {
    88  		if len(customMessage) > 0 {
    89  			for k, v := range msg {
    90  				customMessage[k] = v
    91  			}
    92  		} else {
    93  			customMessage = msg
    94  		}
    95  	}
    96  	var (
    97  		value interface{}
    98  	)
    99  	for _, checkRuleItem := range checkRules {
   100  		if len(checkRuleItem.Rule) == 0 {
   101  			continue
   102  		}
   103  		value = nil
   104  		if valueItem, ok := data[checkRuleItem.Name]; ok {
   105  			value = valueItem
   106  		}
   107  		// It checks each rule and its value in loop.
   108  		if validatedError := v.doCheckValue(doCheckValueInput{
   109  			Name:     checkRuleItem.Name,
   110  			Value:    value,
   111  			Rule:     checkRuleItem.Rule,
   112  			Messages: customMessage[checkRuleItem.Name],
   113  			DataRaw:  params,
   114  			DataMap:  data,
   115  		}); validatedError != nil {
   116  			_, errorItem := validatedError.FirstItem()
   117  			// ===========================================================
   118  			// Only in map and struct validations, if value is nil or empty
   119  			// string and has no required* rules, it clears the error message.
   120  			// ===========================================================
   121  			if gconv.String(value) == "" {
   122  				required := false
   123  				// rule => error
   124  				for ruleKey := range errorItem {
   125  					// Default required rules.
   126  					if _, ok := mustCheckRulesEvenValueEmpty[ruleKey]; ok {
   127  						required = true
   128  						break
   129  					}
   130  					// Custom rules are also required in default.
   131  					if f := v.getRuleFunc(ruleKey); f != nil {
   132  						required = true
   133  						break
   134  					}
   135  				}
   136  				if !required {
   137  					continue
   138  				}
   139  			}
   140  			if _, ok := errorMaps[checkRuleItem.Name]; !ok {
   141  				errorMaps[checkRuleItem.Name] = make(map[string]string)
   142  			}
   143  			for ruleKey, errorItemMsgMap := range errorItem {
   144  				errorMaps[checkRuleItem.Name][ruleKey] = errorItemMsgMap
   145  			}
   146  			if v.bail {
   147  				break
   148  			}
   149  		}
   150  	}
   151  	if len(errorMaps) > 0 {
   152  		return newError(gcode.CodeValidationFailed, checkRules, errorMaps)
   153  	}
   154  	return nil
   155  }