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  }