github.com/gogf/gf@v1.16.9/util/gvalid/gvalid_error.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/errors/gerror"
    12  	"github.com/gogf/gf/text/gregex"
    13  	"github.com/gogf/gf/text/gstr"
    14  	"strings"
    15  )
    16  
    17  // Error is the validation error for validation result.
    18  type Error interface {
    19  	Code() gcode.Code
    20  	Current() error
    21  	Error() string
    22  	FirstItem() (key string, messages map[string]string)
    23  	FirstRule() (rule string, err string)
    24  	FirstString() (err string)
    25  	Items() (items []map[string]map[string]string)
    26  	Map() map[string]string
    27  	Maps() map[string]map[string]string
    28  	String() string
    29  	Strings() (errs []string)
    30  }
    31  
    32  // validationError is the validation error for validation result.
    33  type validationError struct {
    34  	code      gcode.Code                   // Error code.
    35  	rules     []fieldRule                  // Rules by sequence, which is used for keeping error sequence.
    36  	errors    map[string]map[string]string // Error map:map[field]map[rule]message
    37  	firstKey  string                       // The first error rule key(empty in default).
    38  	firstItem map[string]string            // The first error rule value(nil in default).
    39  }
    40  
    41  // newError creates and returns a validation error.
    42  func newError(code gcode.Code, rules []fieldRule, errors map[string]map[string]string) *validationError {
    43  	for field, m := range errors {
    44  		for k, v := range m {
    45  			v = strings.Replace(v, ":attribute", field, -1)
    46  			v, _ = gregex.ReplaceString(`\s{2,}`, ` `, v)
    47  			v = gstr.Trim(v)
    48  			m[k] = v
    49  		}
    50  		errors[field] = m
    51  	}
    52  	return &validationError{
    53  		code:   code,
    54  		rules:  rules,
    55  		errors: errors,
    56  	}
    57  }
    58  
    59  // newErrorStr creates and returns a validation error by string.
    60  func newErrorStr(key, err string) *validationError {
    61  	return newError(gcode.CodeInternalError, nil, map[string]map[string]string{
    62  		internalErrorMapKey: {
    63  			key: err,
    64  		},
    65  	})
    66  }
    67  
    68  // Code returns the error code of current validation error.
    69  func (e *validationError) Code() gcode.Code {
    70  	if e == nil {
    71  		return gcode.CodeNil
    72  	}
    73  	return e.code
    74  }
    75  
    76  // Map returns the first error message as map.
    77  func (e *validationError) Map() map[string]string {
    78  	if e == nil {
    79  		return map[string]string{}
    80  	}
    81  	_, m := e.FirstItem()
    82  	return m
    83  }
    84  
    85  // Maps returns all error messages as map.
    86  func (e *validationError) Maps() map[string]map[string]string {
    87  	if e == nil {
    88  		return nil
    89  	}
    90  	return e.errors
    91  }
    92  
    93  // Items retrieves and returns error items array in sequence if possible,
    94  // or else it returns error items with no sequence .
    95  func (e *validationError) Items() (items []map[string]map[string]string) {
    96  	if e == nil {
    97  		return []map[string]map[string]string{}
    98  	}
    99  	items = make([]map[string]map[string]string, 0)
   100  	// By sequence.
   101  	if len(e.rules) > 0 {
   102  		for _, v := range e.rules {
   103  			if errorItemMap, ok := e.errors[v.Name]; ok {
   104  				items = append(items, map[string]map[string]string{
   105  					v.Name: errorItemMap,
   106  				})
   107  			}
   108  		}
   109  		return items
   110  	}
   111  	// No sequence.
   112  	for name, errorRuleMap := range e.errors {
   113  		items = append(items, map[string]map[string]string{
   114  			name: errorRuleMap,
   115  		})
   116  	}
   117  	return
   118  }
   119  
   120  // FirstItem returns the field name and error messages for the first validation rule error.
   121  func (e *validationError) FirstItem() (key string, messages map[string]string) {
   122  	if e == nil {
   123  		return "", map[string]string{}
   124  	}
   125  	if e.firstItem != nil {
   126  		return e.firstKey, e.firstItem
   127  	}
   128  	// By sequence.
   129  	if len(e.rules) > 0 {
   130  		for _, v := range e.rules {
   131  			if errorItemMap, ok := e.errors[v.Name]; ok {
   132  				e.firstKey = v.Name
   133  				e.firstItem = errorItemMap
   134  				return v.Name, errorItemMap
   135  			}
   136  		}
   137  	}
   138  	// No sequence.
   139  	for k, m := range e.errors {
   140  		e.firstKey = k
   141  		e.firstItem = m
   142  		return k, m
   143  	}
   144  	return "", nil
   145  }
   146  
   147  // FirstRule returns the first error rule and message string.
   148  func (e *validationError) FirstRule() (rule string, err string) {
   149  	if e == nil {
   150  		return "", ""
   151  	}
   152  	// By sequence.
   153  	if len(e.rules) > 0 {
   154  		for _, v := range e.rules {
   155  			if errorItemMap, ok := e.errors[v.Name]; ok {
   156  				for _, ruleItem := range strings.Split(v.Rule, "|") {
   157  					array := strings.Split(ruleItem, ":")
   158  					ruleItem = strings.TrimSpace(array[0])
   159  					if err, ok = errorItemMap[ruleItem]; ok {
   160  						return ruleItem, err
   161  					}
   162  				}
   163  			}
   164  		}
   165  	}
   166  	// No sequence.
   167  	for _, errorItemMap := range e.errors {
   168  		for k, v := range errorItemMap {
   169  			return k, v
   170  		}
   171  	}
   172  	return "", ""
   173  }
   174  
   175  // FirstString returns the first error message as string.
   176  // Note that the returned message might be different if it has no sequence.
   177  func (e *validationError) FirstString() (err string) {
   178  	if e == nil {
   179  		return ""
   180  	}
   181  	_, err = e.FirstRule()
   182  	return
   183  }
   184  
   185  // Current is alis of FirstString, which implements interface gerror.ApiCurrent.
   186  func (e *validationError) Current() error {
   187  	if e == nil {
   188  		return nil
   189  	}
   190  	_, err := e.FirstRule()
   191  	return gerror.NewCode(e.code, err)
   192  }
   193  
   194  // String returns all error messages as string, multiple error messages joined using char ';'.
   195  func (e *validationError) String() string {
   196  	if e == nil {
   197  		return ""
   198  	}
   199  	return strings.Join(e.Strings(), "; ")
   200  }
   201  
   202  // Error implements interface of error.Error.
   203  func (e *validationError) Error() string {
   204  	if e == nil {
   205  		return ""
   206  	}
   207  	return e.String()
   208  }
   209  
   210  // Strings returns all error messages as string array.
   211  func (e *validationError) Strings() (errs []string) {
   212  	if e == nil {
   213  		return []string{}
   214  	}
   215  	errs = make([]string, 0)
   216  	// By sequence.
   217  	if len(e.rules) > 0 {
   218  		for _, v := range e.rules {
   219  			if errorItemMap, ok := e.errors[v.Name]; ok {
   220  				// validation error checks.
   221  				for _, ruleItem := range strings.Split(v.Rule, "|") {
   222  					ruleItem = strings.TrimSpace(strings.Split(ruleItem, ":")[0])
   223  					if err, ok := errorItemMap[ruleItem]; ok {
   224  						errs = append(errs, err)
   225  					}
   226  				}
   227  				// internal error checks.
   228  				for k, _ := range internalErrKeyMap {
   229  					if err, ok := errorItemMap[k]; ok {
   230  						errs = append(errs, err)
   231  					}
   232  				}
   233  			}
   234  		}
   235  		return errs
   236  	}
   237  	// No sequence.
   238  	for _, errorItemMap := range e.errors {
   239  		for _, err := range errorItemMap {
   240  			errs = append(errs, err)
   241  		}
   242  	}
   243  	return
   244  }