mirror of
https://gitee.com/johng/gf
synced 2026-06-07 02:12:11 +08:00
improve configuration feature for glog/ghttp.Server
This commit is contained in:
@ -10,12 +10,19 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/internal/structs"
|
||||
"github.com/gogf/gf/internal/utilstr"
|
||||
)
|
||||
|
||||
var (
|
||||
// replaceCharReg is the regular expression object for replacing chars
|
||||
// in map keys and attribute names.
|
||||
replaceCharReg, _ = regexp.Compile(`[\-\.\_\s]+`)
|
||||
)
|
||||
|
||||
// Struct maps the params key-value pairs to the corresponding struct object's properties.
|
||||
// The third parameter <mapping> is unnecessary, indicating the mapping rules between the custom key name
|
||||
// and the attribute name(case sensitive).
|
||||
@ -35,6 +42,7 @@ func Struct(params interface{}, pointer interface{}, mapping ...map[string]strin
|
||||
if pointer == nil {
|
||||
return errors.New("object pointer cannot be nil")
|
||||
}
|
||||
// paramsMap is the map[string]interface{} type variable for params.
|
||||
paramsMap := Map(params)
|
||||
if paramsMap == nil {
|
||||
return fmt.Errorf("invalid params: %v", params)
|
||||
@ -53,7 +61,7 @@ func Struct(params interface{}, pointer interface{}, mapping ...map[string]strin
|
||||
}
|
||||
elem = rv.Elem()
|
||||
}
|
||||
// Auto create struct object.
|
||||
// It automatically creates struct object if necessary.
|
||||
// For example, if <pointer> is **User, then <elem> is *User, which is a pointer to User.
|
||||
if elem.Type().Kind() == reflect.Ptr && (!elem.IsValid() || elem.IsNil()) {
|
||||
e := reflect.New(elem.Type().Elem()).Elem()
|
||||
@ -61,13 +69,14 @@ func Struct(params interface{}, pointer interface{}, mapping ...map[string]strin
|
||||
elem = e
|
||||
}
|
||||
// It only performs one converting to the same attribute.
|
||||
// doneMap is used to check repeated converting.
|
||||
doneMap := make(map[string]bool)
|
||||
// doneMap is used to check repeated converting, its key is the attribute name of the struct.
|
||||
doneMap := make(map[string]struct{})
|
||||
// It first checks the passed mapping rules.
|
||||
if len(mapping) > 0 && len(mapping[0]) > 0 {
|
||||
for mapK, mapV := range mapping[0] {
|
||||
// mapV is the the attribute name of the struct.
|
||||
if v, ok := paramsMap[mapK]; ok {
|
||||
doneMap[mapV] = true
|
||||
doneMap[mapV] = struct{}{}
|
||||
if err := bindVarToStructAttr(elem, mapV, v); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -77,65 +86,67 @@ func Struct(params interface{}, pointer interface{}, mapping ...map[string]strin
|
||||
// It secondly checks the tags of attributes.
|
||||
tagMap := structs.TagMapName(pointer, structTagPriority, true)
|
||||
for tagK, tagV := range tagMap {
|
||||
// tagV is the the attribute name of the struct.
|
||||
if _, ok := doneMap[tagV]; ok {
|
||||
continue
|
||||
}
|
||||
if v, ok := paramsMap[tagK]; ok {
|
||||
doneMap[tagV] = true
|
||||
doneMap[tagV] = struct{}{}
|
||||
if err := bindVarToStructAttr(elem, tagV, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
// It finally do the converting with default rules.
|
||||
attrMap := make(map[string]struct{})
|
||||
// The key of the map is the attribute name of the struct,
|
||||
// and the value is its replaced name for later comparison to improve performance.
|
||||
attrMap := make(map[string]string)
|
||||
elemType := elem.Type()
|
||||
tempName := ""
|
||||
for i := 0; i < elem.NumField(); i++ {
|
||||
// Only do converting to public attributes.
|
||||
if !utilstr.IsLetterUpper(elemType.Field(i).Name[0]) {
|
||||
continue
|
||||
}
|
||||
attrMap[elemType.Field(i).Name] = struct{}{}
|
||||
tempName = elemType.Field(i).Name
|
||||
attrMap[tempName] = replaceCharReg.ReplaceAllString(tempName, "")
|
||||
}
|
||||
if len(attrMap) == 0 {
|
||||
return nil
|
||||
}
|
||||
var attrName, checkName string
|
||||
for mapK, mapV := range paramsMap {
|
||||
name := ""
|
||||
for _, checkName := range []string{
|
||||
utilstr.UcFirst(mapK),
|
||||
utilstr.ReplaceByMap(mapK, map[string]string{
|
||||
"_": "",
|
||||
"-": "",
|
||||
" ": "",
|
||||
})} {
|
||||
if _, ok := doneMap[checkName]; ok {
|
||||
continue
|
||||
}
|
||||
if _, ok := tagMap[checkName]; ok {
|
||||
continue
|
||||
}
|
||||
// Loop to find the matched attribute name.
|
||||
for value, _ := range attrMap {
|
||||
if strings.EqualFold(checkName, value) {
|
||||
name = value
|
||||
break
|
||||
}
|
||||
if strings.EqualFold(checkName, strings.Replace(value, "_", "", -1)) {
|
||||
name = value
|
||||
break
|
||||
}
|
||||
}
|
||||
doneMap[checkName] = true
|
||||
if name != "" {
|
||||
attrName = ""
|
||||
checkName = replaceCharReg.ReplaceAllString(mapK, "")
|
||||
// Loop to find the matched attribute name with or without
|
||||
// string cases and chars like '-'/'_'/'.'/' '.
|
||||
for attrK, attrV := range attrMap {
|
||||
// Eg:
|
||||
// UserName eq user_name
|
||||
// User-Name eq username
|
||||
// username eq userName
|
||||
// etc.
|
||||
if strings.EqualFold(checkName, attrV) {
|
||||
attrName = attrK
|
||||
break
|
||||
}
|
||||
}
|
||||
// If the attribute name is already checked converting, then skip it.
|
||||
if attrName != "" {
|
||||
if _, ok := doneMap[attrName]; ok {
|
||||
continue
|
||||
}
|
||||
if _, ok := tagMap[attrName]; ok {
|
||||
continue
|
||||
}
|
||||
}
|
||||
// No matching, give up this attribute converting.
|
||||
if name == "" {
|
||||
if attrName == "" {
|
||||
continue
|
||||
}
|
||||
if err := bindVarToStructAttr(elem, name, mapV); err != nil {
|
||||
// Mark it done.
|
||||
doneMap[attrName] = struct{}{}
|
||||
if err := bindVarToStructAttr(elem, attrName, mapV); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,11 +7,42 @@
|
||||
// Package gutil provides utility functions.
|
||||
package gutil
|
||||
|
||||
// CopyMap does memory from map <data> to <copy>.
|
||||
func CopyMap(data map[string]interface{}) (copy map[string]interface{}) {
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
// replaceCharReg is the regular expression object for replacing chars in map keys.
|
||||
replaceCharReg, _ = regexp.Compile(`[\-\.\_\s]+`)
|
||||
)
|
||||
|
||||
// MapCopy does memory from map <data> to <copy>.
|
||||
func MapCopy(data map[string]interface{}) (copy map[string]interface{}) {
|
||||
copy = make(map[string]interface{}, len(data))
|
||||
for k, v := range data {
|
||||
copy[k] = v
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// MapValueForPossibleKey tries to find the possible value for given key with or without
|
||||
// cases or chars '-'/'_'/'.'/' '.
|
||||
//
|
||||
// Note that this function might be of low performance.
|
||||
func MapPossibleValueForKey(data map[string]interface{}, key string) interface{} {
|
||||
if v, ok := data[key]; ok {
|
||||
return v
|
||||
}
|
||||
replacedKey := replaceCharReg.ReplaceAllString(key, "")
|
||||
if v, ok := data[replacedKey]; ok {
|
||||
return v
|
||||
}
|
||||
// Loop for check.
|
||||
for k, v := range data {
|
||||
if strings.EqualFold(replaceCharReg.ReplaceAllString(k, ""), replacedKey) {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user