mirror of
https://gitee.com/johng/gf.git
synced 2024-11-30 03:07:45 +08:00
259 lines
6.5 KiB
Go
259 lines
6.5 KiB
Go
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
|
//
|
|
// This Source Code Form is subject to the terms of the MIT License.
|
|
// If a copy of the MIT was not distributed with this file,
|
|
// You can obtain one at https://github.com/gogf/gf.
|
|
|
|
package gvalid
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/gogf/gf/v2/container/gset"
|
|
"github.com/gogf/gf/v2/errors/gcode"
|
|
"github.com/gogf/gf/v2/errors/gerror"
|
|
"github.com/gogf/gf/v2/text/gstr"
|
|
)
|
|
|
|
// Error is the validation error for validation result.
|
|
type Error interface {
|
|
Code() gcode.Code
|
|
Current() error
|
|
Error() string
|
|
FirstItem() (key string, messages map[string]error)
|
|
FirstRule() (rule string, err error)
|
|
FirstError() (err error)
|
|
Items() (items []map[string]map[string]error)
|
|
Map() map[string]error
|
|
Maps() map[string]map[string]error
|
|
String() string
|
|
Strings() (errs []string)
|
|
}
|
|
|
|
// validationError is the validation error for validation result.
|
|
type validationError struct {
|
|
code gcode.Code // Error code.
|
|
rules []fieldRule // Rules by sequence, which is used for keeping error sequence only.
|
|
errors map[string]map[string]error // Error map:map[field]map[rule]message
|
|
firstKey string // The first error rule key(empty in default).
|
|
firstItem map[string]error // The first error rule value(nil in default).
|
|
}
|
|
|
|
// newValidationError creates and returns a validation error.
|
|
func newValidationError(code gcode.Code, rules []fieldRule, fieldRuleErrorMap map[string]map[string]error) *validationError {
|
|
for field, ruleErrorMap := range fieldRuleErrorMap {
|
|
for rule, err := range ruleErrorMap {
|
|
if !gerror.HasStack(err) {
|
|
ruleErrorMap[rule] = gerror.NewWithOption(gerror.Option{
|
|
Stack: false,
|
|
Text: gstr.Trim(err.Error()),
|
|
Code: code,
|
|
})
|
|
}
|
|
}
|
|
fieldRuleErrorMap[field] = ruleErrorMap
|
|
}
|
|
// Filter repeated sequence rules.
|
|
var ruleNameSet = gset.NewStrSet()
|
|
for i := 0; i < len(rules); {
|
|
if !ruleNameSet.AddIfNotExist(rules[i].Name) {
|
|
// Delete repeated rule.
|
|
rules = append(rules[:i], rules[i+1:]...)
|
|
continue
|
|
}
|
|
i++
|
|
}
|
|
return &validationError{
|
|
code: code,
|
|
rules: rules,
|
|
errors: fieldRuleErrorMap,
|
|
}
|
|
}
|
|
|
|
// newValidationErrorByStr creates and returns a validation error by string.
|
|
func newValidationErrorByStr(key string, err error) *validationError {
|
|
return newValidationError(
|
|
gcode.CodeInternalError,
|
|
nil,
|
|
map[string]map[string]error{
|
|
internalErrorMapKey: {
|
|
key: err,
|
|
},
|
|
},
|
|
)
|
|
}
|
|
|
|
// Code returns the error code of current validation error.
|
|
func (e *validationError) Code() gcode.Code {
|
|
if e == nil {
|
|
return gcode.CodeNil
|
|
}
|
|
return e.code
|
|
}
|
|
|
|
// Map returns the first error message as map.
|
|
func (e *validationError) Map() map[string]error {
|
|
if e == nil {
|
|
return map[string]error{}
|
|
}
|
|
_, m := e.FirstItem()
|
|
return m
|
|
}
|
|
|
|
// Maps returns all error messages as map.
|
|
func (e *validationError) Maps() map[string]map[string]error {
|
|
if e == nil {
|
|
return nil
|
|
}
|
|
return e.errors
|
|
}
|
|
|
|
// Items retrieves and returns error items array in sequence if possible,
|
|
// or else it returns error items with no sequence .
|
|
func (e *validationError) Items() (items []map[string]map[string]error) {
|
|
if e == nil {
|
|
return []map[string]map[string]error{}
|
|
}
|
|
items = make([]map[string]map[string]error, 0)
|
|
// By sequence.
|
|
if len(e.rules) > 0 {
|
|
for _, v := range e.rules {
|
|
if errorItemMap, ok := e.errors[v.Name]; ok {
|
|
items = append(items, map[string]map[string]error{
|
|
v.Name: errorItemMap,
|
|
})
|
|
}
|
|
}
|
|
return items
|
|
}
|
|
// No sequence.
|
|
for name, errorRuleMap := range e.errors {
|
|
items = append(items, map[string]map[string]error{
|
|
name: errorRuleMap,
|
|
})
|
|
}
|
|
return
|
|
}
|
|
|
|
// FirstItem returns the field name and error messages for the first validation rule error.
|
|
func (e *validationError) FirstItem() (key string, messages map[string]error) {
|
|
if e == nil {
|
|
return "", map[string]error{}
|
|
}
|
|
if e.firstItem != nil {
|
|
return e.firstKey, e.firstItem
|
|
}
|
|
// By sequence.
|
|
if len(e.rules) > 0 {
|
|
for _, v := range e.rules {
|
|
if errorItemMap, ok := e.errors[v.Name]; ok {
|
|
e.firstKey = v.Name
|
|
e.firstItem = errorItemMap
|
|
return v.Name, errorItemMap
|
|
}
|
|
}
|
|
}
|
|
// No sequence.
|
|
for k, m := range e.errors {
|
|
e.firstKey = k
|
|
e.firstItem = m
|
|
return k, m
|
|
}
|
|
return "", nil
|
|
}
|
|
|
|
// FirstRule returns the first error rule and message string.
|
|
func (e *validationError) FirstRule() (rule string, err error) {
|
|
if e == nil {
|
|
return "", nil
|
|
}
|
|
// By sequence.
|
|
if len(e.rules) > 0 {
|
|
for _, v := range e.rules {
|
|
if errorItemMap, ok := e.errors[v.Name]; ok {
|
|
for _, ruleItem := range strings.Split(v.Rule, "|") {
|
|
array := strings.Split(ruleItem, ":")
|
|
ruleItem = strings.TrimSpace(array[0])
|
|
if err, ok = errorItemMap[ruleItem]; ok {
|
|
return ruleItem, err
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// No sequence.
|
|
for _, errorItemMap := range e.errors {
|
|
for k, v := range errorItemMap {
|
|
return k, v
|
|
}
|
|
}
|
|
return "", nil
|
|
}
|
|
|
|
// FirstError returns the first error message as string.
|
|
// Note that the returned message might be different if it has no sequence.
|
|
func (e *validationError) FirstError() (err error) {
|
|
if e == nil {
|
|
return nil
|
|
}
|
|
_, err = e.FirstRule()
|
|
return
|
|
}
|
|
|
|
// Current is alis of FirstError, which implements interface gerror.iCurrent.
|
|
func (e *validationError) Current() error {
|
|
return e.FirstError()
|
|
}
|
|
|
|
// String returns all error messages as string, multiple error messages joined using char ';'.
|
|
func (e *validationError) String() string {
|
|
if e == nil {
|
|
return ""
|
|
}
|
|
return strings.Join(e.Strings(), "; ")
|
|
}
|
|
|
|
// Error implements interface of error.Error.
|
|
func (e *validationError) Error() string {
|
|
if e == nil {
|
|
return ""
|
|
}
|
|
return e.String()
|
|
}
|
|
|
|
// Strings returns all error messages as string array.
|
|
func (e *validationError) Strings() (errs []string) {
|
|
if e == nil {
|
|
return []string{}
|
|
}
|
|
errs = make([]string, 0)
|
|
// By sequence.
|
|
if len(e.rules) > 0 {
|
|
for _, v := range e.rules {
|
|
if errorItemMap, ok := e.errors[v.Name]; ok {
|
|
// validation error checks.
|
|
for _, ruleItem := range strings.Split(v.Rule, "|") {
|
|
ruleItem = strings.TrimSpace(strings.Split(ruleItem, ":")[0])
|
|
if err, ok := errorItemMap[ruleItem]; ok {
|
|
errs = append(errs, err.Error())
|
|
}
|
|
}
|
|
// internal error checks.
|
|
for k := range internalErrKeyMap {
|
|
if err, ok := errorItemMap[k]; ok {
|
|
errs = append(errs, err.Error())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return errs
|
|
}
|
|
// No sequence.
|
|
for _, errorItemMap := range e.errors {
|
|
for _, err := range errorItemMap {
|
|
errs = append(errs, err.Error())
|
|
}
|
|
}
|
|
return
|
|
}
|