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:
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user