1
0
mirror of https://github.com/kataras/iris.git synced 2026-01-10 05:25:58 +00:00

MVC improvements: add HandleWebsocket that now registers events automatically based on the struct's methods(!) and fix a bug when more than one value of the same type is registered to a static field of a controller

Former-commit-id: e369d1426ac1a6b58314930a18362670317da3c1
This commit is contained in:
Gerasimos (Makis) Maropoulos
2019-07-09 12:16:19 +03:00
parent 85666da682
commit 450f20902d
18 changed files with 383 additions and 183 deletions

View File

@@ -1,6 +1,8 @@
package di
import "reflect"
import (
"reflect"
)
// EmptyIn is just an empty slice of reflect.Value.
var EmptyIn = []reflect.Value{}
@@ -164,6 +166,13 @@ func structFieldIgnored(f reflect.StructField) bool {
return s == "true" // if has an ignore tag then ignore it.
}
// for controller's fields only. Explicit set a stateless to a field
// in order to make the controller a Stateless one even if no other dynamic dependencies exist.
func structFieldStateless(f reflect.StructField) bool {
s := f.Tag.Get("stateless")
return s == "true"
}
type field struct {
Type reflect.Type
Name string // the actual name.
@@ -190,7 +199,7 @@ func lookupFields(elemTyp reflect.Type, skipUnexported bool, parentIndex []int)
for i, n := 0, elemTyp.NumField(); i < n; i++ {
f := elemTyp.Field(i)
if IndirectType(f.Type).Kind() == reflect.Struct &&
!structFieldIgnored(f) {
!structFieldIgnored(f) && !structFieldStateless(f) {
fields = append(fields, lookupFields(f.Type, skipUnexported, append(parentIndex, i))...)
continue
}
@@ -230,7 +239,8 @@ func LookupNonZeroFieldsValues(v reflect.Value, skipUnexported bool) (bindValues
for _, f := range fields {
if fieldVal := elem.FieldByIndex(f.Index); /*f.Type.Kind() == reflect.Ptr &&*/
!IsZero(fieldVal) {
goodVal(fieldVal) && !IsZero(fieldVal) {
// fmt.Printf("[%d][field index = %d] append to bindValues: %s = %s\n", i, f.Index[0], f.Name, fieldVal.String())
bindValues = append(bindValues, fieldVal)
}
}

View File

@@ -20,6 +20,22 @@ const (
Singleton
)
// read-only on runtime.
var scopeNames = map[Scope]string{
Stateless: "Stateless",
Singleton: "Singleton",
}
// Return "Stateless" for 0 or "Singleton" for 1.
func (scope Scope) String() string {
name, ok := scopeNames[scope]
if !ok {
return "Unknown"
}
return name
}
type (
targetStructField struct {
Object *BindObject
@@ -65,6 +81,20 @@ func MakeStructInjector(v reflect.Value, hijack Hijacker, goodFunc TypeChecker,
elemType: IndirectType(v.Type()),
}
// Optionally check and keep good values only here,
// but not required because they are already checked by users of this function.
//
// for i, v := range values {
// if !goodVal(v) || IsZero(v) {
// if last := len(values) - 1; last > i {
// values = append(values[:i], values[i+1:]...)
// } else {
// values = values[0:last]
// }
// }
// }
visited := make(map[int]struct{}, 0) // add a visited to not add twice a single value (09-Jul-2019).
fields := lookupFields(s.elemType, true, nil)
for _, f := range fields {
if hijack != nil {
@@ -78,15 +108,19 @@ func MakeStructInjector(v reflect.Value, hijack Hijacker, goodFunc TypeChecker,
}
}
for _, val := range values {
for idx, val := range values {
if _, alreadySet := visited[idx]; alreadySet {
continue
}
// the binded values to the struct's fields.
b, err := MakeBindObject(val, goodFunc)
if err != nil {
return s // if error stop here.
}
if b.IsAssignable(f.Type) {
visited[idx] = struct{}{}
// fmt.Printf("bind the object to the field: %s at index: %#v and type: %s\n", f.Name, f.Index, f.Type.String())
s.fields = append(s.fields, &targetStructField{
FieldIndex: f.Index,
@@ -126,13 +160,14 @@ func (s *StructInjector) setState() {
// if so then set the temp staticBindingsFieldsLength to that number, so for example:
// if static binding length is 0
// but an unexported field is set-ed then act that as singleton.
if allStructFieldsLength > staticBindingsFieldsLength {
structFieldsUnexportedNonZero := LookupNonZeroFieldsValues(s.initRef, false)
staticBindingsFieldsLength = len(structFieldsUnexportedNonZero)
}
// println("staticBindingsFieldsLength: ", staticBindingsFieldsLength)
// println("allStructFieldsLength: ", allStructFieldsLength)
// println("staticBindingsFieldsLength: ", staticBindingsFieldsLength)
// if the number of static values binded is equal to the
// total struct's fields(including unexported fields this time) then set as singleton.
@@ -169,9 +204,23 @@ func (s *StructInjector) fillStruct() {
func (s *StructInjector) String() (trace string) {
for i, f := range s.fields {
elemField := s.elemType.FieldByIndex(f.FieldIndex)
trace += fmt.Sprintf("[%d] %s binding: '%s' for field '%s %s'\n",
i+1, bindTypeString(f.Object.BindType), f.Object.Type.String(),
elemField.Name, elemField.Type.String())
format := "\t[%d] %s binding: %#+v for field '%s %s'"
if len(s.fields) > i+1 {
format += "\n"
}
if !f.Object.Value.IsValid() {
continue // probably a Context.
}
valuePresent := f.Object.Value.Interface()
if f.Object.BindType == Dynamic {
valuePresent = f.Object.Type.String()
}
trace += fmt.Sprintf(format, i+1, bindTypeString(f.Object.BindType), valuePresent, elemField.Name, elemField.Type.String())
}
return

View File

@@ -29,7 +29,22 @@ func (bv Values) CloneWithFieldsOf(s interface{}) Values {
// add the manual filled fields to the dependencies.
filledFieldValues := LookupNonZeroFieldsValues(ValueOf(s), true)
for i, filled := range filledFieldValues {
for _, v := range values {
// do NOT keep duplicate equal values (09-Jul-2019).
if reflect.DeepEqual(v, filled) {
if last := len(filledFieldValues) - 1; last > i {
filledFieldValues = append(filledFieldValues[:i], filledFieldValues[i+1:]...)
} else {
filledFieldValues = filledFieldValues[0:last]
}
break
}
}
}
values = append(values, filledFieldValues...)
return values
}