mirror of
https://gitee.com/johng/gf.git
synced 2024-11-30 03:07:45 +08:00
merge develop
This commit is contained in:
commit
baf51bc68f
@ -140,6 +140,7 @@ please note your github/gitee account in your payment bill. All the donations wi
|
||||
|RAGGA-TIME|alipay|¥50.00|
|
||||
|[ChArmy](https://gitee.com/charmy)|alipay|¥50.00|
|
||||
|[sanfenzui](https://gitee.com/sanfenzui)|alipay|¥88.00|
|
||||
|刘宇|wechat|¥30.00|请你喝咖啡
|
||||
|
||||
|
||||
|
||||
|
@ -199,3 +199,10 @@ func (m *Model) Safe(safe ...bool) *Model {
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// Args sets custom arguments for model operation.
|
||||
func (m *Model) Args(args ...interface{}) *Model {
|
||||
model := m.getModel()
|
||||
model.extraArgs = append(model.extraArgs, args)
|
||||
return model
|
||||
}
|
||||
|
@ -42,6 +42,8 @@ func (m *Model) Fields(fieldNamesOrMapStruct ...interface{}) *Model {
|
||||
switch r := fieldNamesOrMapStruct[0].(type) {
|
||||
case string:
|
||||
model.fields = gstr.Join(m.mappingToTableFields([]string{r}), ",")
|
||||
case []string:
|
||||
model.fields = gstr.Join(m.mappingToTableFields(r), ",")
|
||||
default:
|
||||
model.fields = gstr.Join(m.mappingToTableFields(gutil.Keys(r)), ",")
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ package ghtml
|
||||
|
||||
import (
|
||||
"html"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
strip "github.com/grokify/html-strip-tags-go"
|
||||
@ -57,3 +58,46 @@ func SpecialCharsDecode(s string) string {
|
||||
"'", "'",
|
||||
).Replace(s)
|
||||
}
|
||||
|
||||
// SpecialCharsMapOrStruct automatically encodes string values/attributes for map/struct.
|
||||
func SpecialCharsMapOrStruct(mapOrStruct interface{}) error {
|
||||
var (
|
||||
reflectValue = reflect.ValueOf(mapOrStruct)
|
||||
reflectKind = reflectValue.Kind()
|
||||
)
|
||||
for reflectValue.IsValid() && (reflectKind == reflect.Ptr || reflectKind == reflect.Interface) {
|
||||
reflectValue = reflectValue.Elem()
|
||||
reflectKind = reflectValue.Kind()
|
||||
}
|
||||
switch reflectKind {
|
||||
case reflect.Map:
|
||||
var (
|
||||
mapKeys = reflectValue.MapKeys()
|
||||
mapValue reflect.Value
|
||||
)
|
||||
for _, key := range mapKeys {
|
||||
mapValue = reflectValue.MapIndex(key)
|
||||
switch mapValue.Kind() {
|
||||
case reflect.String:
|
||||
reflectValue.SetMapIndex(key, reflect.ValueOf(SpecialChars(mapValue.String())))
|
||||
case reflect.Interface:
|
||||
if mapValue.Elem().Kind() == reflect.String {
|
||||
reflectValue.SetMapIndex(key, reflect.ValueOf(SpecialChars(mapValue.Elem().String())))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case reflect.Struct:
|
||||
var (
|
||||
fieldValue reflect.Value
|
||||
)
|
||||
for i := 0; i < reflectValue.NumField(); i++ {
|
||||
fieldValue = reflectValue.Field(i)
|
||||
switch fieldValue.Kind() {
|
||||
case reflect.String:
|
||||
fieldValue.Set(reflect.ValueOf(SpecialChars(fieldValue.String())))
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -7,13 +7,14 @@
|
||||
package ghtml_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/encoding/ghtml"
|
||||
"github.com/gogf/gf/test/gtest"
|
||||
)
|
||||
|
||||
func TestStripTags(t *testing.T) {
|
||||
func Test_StripTags(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
src := `<p>Test paragraph.</p><!-- Comment --> <a href="#fragment">Other text</a>`
|
||||
dst := `Test paragraph. Other text`
|
||||
@ -21,7 +22,7 @@ func TestStripTags(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestEntities(t *testing.T) {
|
||||
func Test_Entities(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
src := `A 'quote' "is" <b>bold</b>`
|
||||
dst := `A 'quote' "is" <b>bold</b>`
|
||||
@ -30,7 +31,7 @@ func TestEntities(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestSpecialChars(t *testing.T) {
|
||||
func Test_SpecialChars(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
src := `A 'quote' "is" <b>bold</b>`
|
||||
dst := `A 'quote' "is" <b>bold</b>`
|
||||
@ -38,3 +39,43 @@ func TestSpecialChars(t *testing.T) {
|
||||
t.Assert(ghtml.SpecialCharsDecode(dst), src)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_SpecialCharsMapOrStruct_Map(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
a := g.Map{
|
||||
"Title": "<h1>T</h1>",
|
||||
"Content": "<div>C</div>",
|
||||
}
|
||||
err := ghtml.SpecialCharsMapOrStruct(a)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(a["Title"], `<h1>T</h1>`)
|
||||
t.Assert(a["Content"], `<div>C</div>`)
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
a := g.MapStrStr{
|
||||
"Title": "<h1>T</h1>",
|
||||
"Content": "<div>C</div>",
|
||||
}
|
||||
err := ghtml.SpecialCharsMapOrStruct(a)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(a["Title"], `<h1>T</h1>`)
|
||||
t.Assert(a["Content"], `<div>C</div>`)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_SpecialCharsMapOrStruct_Struct(t *testing.T) {
|
||||
type A struct {
|
||||
Title string
|
||||
Content string
|
||||
}
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
a := &A{
|
||||
Title: "<h1>T</h1>",
|
||||
Content: "<div>C</div>",
|
||||
}
|
||||
err := ghtml.SpecialCharsMapOrStruct(a)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(a.Title, `<h1>T</h1>`)
|
||||
t.Assert(a.Content, `<div>C</div>`)
|
||||
})
|
||||
}
|
||||
|
@ -74,13 +74,16 @@ func (r *Response) ParseTplContent(content string, params ...gview.Params) (stri
|
||||
}
|
||||
|
||||
// buildInVars merges build-in variables into <params> and returns the new template variables.
|
||||
// TODO performance improving.
|
||||
func (r *Response) buildInVars(params ...map[string]interface{}) map[string]interface{} {
|
||||
m := gutil.MapMergeCopy(params...)
|
||||
m := gutil.MapMergeCopy(r.Request.viewParams)
|
||||
if len(params) > 0 {
|
||||
gutil.MapMerge(m, params[0])
|
||||
}
|
||||
// Retrieve custom template variables from request object.
|
||||
gutil.MapMerge(m, r.Request.viewParams, map[string]interface{}{
|
||||
gutil.MapMerge(m, map[string]interface{}{
|
||||
"Form": r.Request.GetFormMap(),
|
||||
"Query": r.Request.GetQueryMap(),
|
||||
"Request": r.Request.GetMap(),
|
||||
"Cookie": r.Request.Cookie.Map(),
|
||||
"Session": r.Request.Session.Map(),
|
||||
})
|
||||
|
@ -175,8 +175,8 @@ func (s *Server) searchHandlers(method, path, domain string) (parsedItems []*han
|
||||
parsedItemList.PushBack(parsedItem)
|
||||
|
||||
// The middleware is inserted before the serving handler.
|
||||
// If there're multiple middlewares, they're inserted into the result list by their registering order.
|
||||
// The middlewares are also executed by their registering order.
|
||||
// If there're multiple middleware, they're inserted into the result list by their registering order.
|
||||
// The middleware are also executed by their registered order.
|
||||
case gHANDLER_TYPE_MIDDLEWARE:
|
||||
if lastMiddlewareElem == nil {
|
||||
lastMiddlewareElem = parsedItemList.PushFront(parsedItem)
|
||||
|
@ -50,6 +50,11 @@ func doStruct(params interface{}, pointer interface{}, mapping ...map[string]str
|
||||
if pointer == nil {
|
||||
return gerror.New("object pointer cannot be nil")
|
||||
}
|
||||
|
||||
if doStructByDirectReflectSet(params, pointer) {
|
||||
return nil
|
||||
}
|
||||
|
||||
defer func() {
|
||||
// Catch the panic, especially the reflect operation panics.
|
||||
if e := recover(); e != nil {
|
||||
@ -255,6 +260,20 @@ func doStruct(params interface{}, pointer interface{}, mapping ...map[string]str
|
||||
return nil
|
||||
}
|
||||
|
||||
// doStructByDirectReflectSet do the converting directly using reflect Set.
|
||||
// It returns true if success, or else false.
|
||||
func doStructByDirectReflectSet(params interface{}, pointer interface{}) (ok bool) {
|
||||
v1 := reflect.ValueOf(pointer)
|
||||
v2 := reflect.ValueOf(params)
|
||||
if v1.Kind() == reflect.Ptr {
|
||||
if elem := v1.Elem(); elem.IsValid() && elem.Type() == v2.Type() {
|
||||
elem.Set(v2)
|
||||
ok = true
|
||||
}
|
||||
}
|
||||
return ok
|
||||
}
|
||||
|
||||
// bindVarToStructAttr sets value to struct object attribute by name.
|
||||
func bindVarToStructAttr(elem reflect.Value, name string, value interface{}, mapping ...map[string]string) (err error) {
|
||||
structFieldValue := elem.FieldByName(name)
|
||||
|
@ -38,6 +38,11 @@ func doStructs(params interface{}, pointer interface{}, mapping ...map[string]st
|
||||
if pointer == nil {
|
||||
return gerror.New("object pointer cannot be nil")
|
||||
}
|
||||
|
||||
if doStructsByDirectReflectSet(params, pointer) {
|
||||
return nil
|
||||
}
|
||||
|
||||
defer func() {
|
||||
// Catch the panic, especially the reflect operation panics.
|
||||
if e := recover(); e != nil {
|
||||
@ -104,5 +109,18 @@ func doStructs(params interface{}, pointer interface{}, mapping ...map[string]st
|
||||
}
|
||||
pointerRv.Elem().Set(array)
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// doStructsByDirectReflectSet do the converting directly using reflect Set.
|
||||
// It returns true if success, or else false.
|
||||
func doStructsByDirectReflectSet(params interface{}, pointer interface{}) (ok bool) {
|
||||
v1 := reflect.ValueOf(pointer)
|
||||
v2 := reflect.ValueOf(params)
|
||||
if v1.Kind() == reflect.Ptr {
|
||||
if elem := v1.Elem(); elem.IsValid() && elem.Type() == v2.Type() {
|
||||
elem.Set(v2)
|
||||
ok = true
|
||||
}
|
||||
}
|
||||
return ok
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
package gconv
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@ -22,7 +23,27 @@ var (
|
||||
"name": "gf",
|
||||
"score": 100,
|
||||
}
|
||||
structPointer = new(structType)
|
||||
structObj = structType{
|
||||
Name: "john",
|
||||
Score: 60,
|
||||
}
|
||||
structPointer = &structType{
|
||||
Name: "john",
|
||||
Score: 60,
|
||||
}
|
||||
structPointerNil *structType
|
||||
// struct slice
|
||||
structSliceNil []structType
|
||||
structSlice = []structType{
|
||||
{Name: "john", Score: 60},
|
||||
{Name: "smith", Score: 100},
|
||||
}
|
||||
// struct pointer slice
|
||||
structPointerSliceNil []*structType
|
||||
structPointerSlice = []*structType{
|
||||
{Name: "john", Score: 60},
|
||||
{Name: "smith", Score: 100},
|
||||
}
|
||||
)
|
||||
|
||||
func Benchmark_Struct_Basic(b *testing.B) {
|
||||
@ -30,3 +51,83 @@ func Benchmark_Struct_Basic(b *testing.B) {
|
||||
Struct(structMap, structPointer)
|
||||
}
|
||||
}
|
||||
|
||||
// *struct -> **struct
|
||||
func Benchmark_Reflect_PPStruct_PStruct(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
v1 := reflect.ValueOf(&structPointerNil)
|
||||
v2 := reflect.ValueOf(structPointer)
|
||||
//if v1.Kind() == reflect.Ptr {
|
||||
// if elem := v1.Elem(); elem.Type() == v2.Type() {
|
||||
// elem.Set(v2)
|
||||
// }
|
||||
//}
|
||||
v1.Elem().Set(v2)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Struct_PPStruct_PStruct(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
Struct(structPointer, &structPointerNil)
|
||||
}
|
||||
}
|
||||
|
||||
// struct -> *struct
|
||||
func Benchmark_Reflect_PStruct_Struct(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
v1 := reflect.ValueOf(structPointer)
|
||||
v2 := reflect.ValueOf(structObj)
|
||||
//if v1.Kind() == reflect.Ptr {
|
||||
// if elem := v1.Elem(); elem.Type() == v2.Type() {
|
||||
// elem.Set(v2)
|
||||
// }
|
||||
//}
|
||||
v1.Elem().Set(v2)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Struct_PStruct_Struct(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
Struct(structObj, structPointer)
|
||||
}
|
||||
}
|
||||
|
||||
// []struct -> *[]struct
|
||||
func Benchmark_Reflect_PStructs_Structs(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
v1 := reflect.ValueOf(&structSliceNil)
|
||||
v2 := reflect.ValueOf(structSlice)
|
||||
//if v1.Kind() == reflect.Ptr {
|
||||
// if elem := v1.Elem(); elem.Type() == v2.Type() {
|
||||
// elem.Set(v2)
|
||||
// }
|
||||
//}
|
||||
v1.Elem().Set(v2)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Structs_PStructs_Structs(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
Structs(structSlice, &structSliceNil)
|
||||
}
|
||||
}
|
||||
|
||||
// []*struct -> *[]*struct
|
||||
func Benchmark_Reflect_PPStructs_PStructs(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
v1 := reflect.ValueOf(&structPointerSliceNil)
|
||||
v2 := reflect.ValueOf(structPointerSlice)
|
||||
//if v1.Kind() == reflect.Ptr {
|
||||
// if elem := v1.Elem(); elem.Type() == v2.Type() {
|
||||
// elem.Set(v2)
|
||||
// }
|
||||
//}
|
||||
v1.Elem().Set(v2)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Structs_PPStructs_PStructs(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
Structs(structPointerSlice, &structPointerSliceNil)
|
||||
}
|
||||
}
|
||||
|
@ -143,3 +143,34 @@ func Test_Struct_SliceWithTag(t *testing.T) {
|
||||
t.Assert(users[1].NickName, "name2")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Structs_DirectReflectSet(t *testing.T) {
|
||||
type A struct {
|
||||
Id int
|
||||
Name string
|
||||
}
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
a = []*A{
|
||||
{Id: 1, Name: "john"},
|
||||
{Id: 2, Name: "smith"},
|
||||
}
|
||||
b []*A
|
||||
)
|
||||
err := gconv.Structs(a, &b)
|
||||
t.Assert(err, nil)
|
||||
t.AssertEQ(a, b)
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
a = []A{
|
||||
{Id: 1, Name: "john"},
|
||||
{Id: 2, Name: "smith"},
|
||||
}
|
||||
b []A
|
||||
)
|
||||
err := gconv.Structs(a, &b)
|
||||
t.Assert(err, nil)
|
||||
t.AssertEQ(a, b)
|
||||
})
|
||||
}
|
||||
|
@ -1003,3 +1003,35 @@ func Test_Struct_AttrStructHasTheSameTag(t *testing.T) {
|
||||
t.Assert(order.Product.UpdatedAtFormat, "")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Struct_DirectReflectSet(t *testing.T) {
|
||||
type A struct {
|
||||
Id int
|
||||
Name string
|
||||
}
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
a = &A{
|
||||
Id: 1,
|
||||
Name: "john",
|
||||
}
|
||||
b *A
|
||||
)
|
||||
err := gconv.Struct(a, &b)
|
||||
t.Assert(err, nil)
|
||||
t.AssertEQ(a, b)
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
a = A{
|
||||
Id: 1,
|
||||
Name: "john",
|
||||
}
|
||||
b A
|
||||
)
|
||||
err := gconv.Struct(a, &b)
|
||||
t.Assert(err, nil)
|
||||
t.AssertEQ(a, b)
|
||||
})
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package gf
|
||||
|
||||
const VERSION = "v1.14.3"
|
||||
const VERSION = "v1.14.4"
|
||||
const AUTHORS = "john<john@goframe.org>"
|
||||
|
Loading…
Reference in New Issue
Block a user