mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 10:41:03 +01:00
create one generic package for dependency injection which can be used outside of Iris too - worked but unfished
Former-commit-id: a9d600321c07d7c9f39105416f14ae91528a16a3
This commit is contained in:
parent
a5fac270cf
commit
4e15f4ea88
|
@ -1,8 +1,10 @@
|
|||
package controllers
|
||||
|
||||
// import "github.com/kataras/iris/mvc2"
|
||||
|
||||
// ValuesController is the equivalent
|
||||
// `ValuesController` of the .net core 2.0 mvc application.
|
||||
type ValuesController struct{}
|
||||
type ValuesController struct{} //{ mvc2.C }
|
||||
|
||||
/* on windows tests(older) the Get was:
|
||||
func (vc *ValuesController) Get() {
|
||||
|
|
|
@ -46,7 +46,7 @@ func main() {
|
|||
|
||||
// using an io.Writer for automatic buffer management (i.e. hero built-in buffer pool),
|
||||
// iris context implements the io.Writer by its ResponseWriter
|
||||
// which is an enhanced version of the standar http.ResponseWriter
|
||||
// which is an enhanced version of the standard http.ResponseWriter
|
||||
// but still 100% compatible.
|
||||
template.UserListToWriter(userList, ctx)
|
||||
})
|
||||
|
|
254
mvc2/bind.go
254
mvc2/bind.go
|
@ -1,258 +1,34 @@
|
|||
package mvc2
|
||||
|
||||
import "reflect"
|
||||
|
||||
type bindType uint32
|
||||
|
||||
const (
|
||||
objectType bindType = iota // simple assignable value.
|
||||
functionResultType // dynamic value, depends on the context.
|
||||
import (
|
||||
"github.com/kataras/di"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type bindObject struct {
|
||||
Type reflect.Type // the Type of 'Value' or the type of the returned 'ReturnValue' .
|
||||
Value reflect.Value
|
||||
|
||||
BindType bindType
|
||||
ReturnValue func(ctx []reflect.Value) reflect.Value
|
||||
}
|
||||
|
||||
// makeReturnValue takes any function
|
||||
// that accept a context and returns something
|
||||
// and returns a binder function, which accepts the context as slice of reflect.Value
|
||||
// and returns a reflect.Value for that.
|
||||
// Iris uses to
|
||||
// resolve and set the input parameters when a handler is executed.
|
||||
//
|
||||
// The "fn" can have the following form:
|
||||
// `func(iris.Context) UserViewModel`.
|
||||
//
|
||||
// The return type of the "fn" should be a value instance, not a pointer, for your own protection.
|
||||
// The binder function should return only one value and
|
||||
// it can accept only one input argument,
|
||||
// the Iris' Context (`context.Context` or `iris.Context`).
|
||||
func makeReturnValue(fn reflect.Value) (func([]reflect.Value) reflect.Value, reflect.Type, error) {
|
||||
typ := indirectTyp(fn.Type())
|
||||
|
||||
// invalid if not a func.
|
||||
if typ.Kind() != reflect.Func {
|
||||
return nil, typ, errBad
|
||||
var (
|
||||
typeChecker = func(fn reflect.Type) bool {
|
||||
// invalid if that single input arg is not a typeof context.Context.
|
||||
return isContext(fn.In(0))
|
||||
}
|
||||
|
||||
// invalid if not returns one single value.
|
||||
if typ.NumOut() != 1 {
|
||||
return nil, typ, errBad
|
||||
}
|
||||
|
||||
// invalid if input args length is not one.
|
||||
if typ.NumIn() != 1 {
|
||||
return nil, typ, errBad
|
||||
}
|
||||
|
||||
// invalid if that single input arg is not a typeof context.Context.
|
||||
if !isContext(typ.In(0)) {
|
||||
return nil, typ, errBad
|
||||
}
|
||||
|
||||
outTyp := typ.Out(0)
|
||||
zeroOutVal := reflect.New(outTyp).Elem()
|
||||
|
||||
bf := func(ctxValue []reflect.Value) reflect.Value {
|
||||
results := fn.Call(ctxValue) // ctxValue is like that because of; read makeHandler.
|
||||
if len(results) == 0 {
|
||||
return zeroOutVal
|
||||
hijacker = func(fieldOrFuncInput reflect.Type) (*di.BindObject, bool) {
|
||||
if isContext(fieldOrFuncInput) {
|
||||
return newContextBindObject(), true
|
||||
}
|
||||
|
||||
v := results[0]
|
||||
if !v.IsValid() {
|
||||
return zeroOutVal
|
||||
}
|
||||
return v
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return bf, outTyp, nil
|
||||
}
|
||||
|
||||
func makeBindObject(v reflect.Value) (b bindObject, err error) {
|
||||
if isFunc(v) {
|
||||
b.BindType = functionResultType
|
||||
b.ReturnValue, b.Type, err = makeReturnValue(v)
|
||||
} else {
|
||||
b.BindType = objectType
|
||||
b.Type = v.Type()
|
||||
b.Value = v
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
)
|
||||
|
||||
// newContextBindObject is being used on both targetFunc and targetStruct.
|
||||
// if the func's input argument or the struct's field is a type of Context
|
||||
// then we can do a fast binding using the ctxValue
|
||||
// which is used as slice of reflect.Value, because of the final method's `Call`.
|
||||
func newContextBindObject() *bindObject {
|
||||
return &bindObject{
|
||||
func newContextBindObject() *di.BindObject {
|
||||
return &di.BindObject{
|
||||
Type: contextTyp,
|
||||
BindType: functionResultType,
|
||||
BindType: di.Dynamic,
|
||||
ReturnValue: func(ctxValue []reflect.Value) reflect.Value {
|
||||
return ctxValue[0]
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (b *bindObject) IsAssignable(to reflect.Type) bool {
|
||||
return equalTypes(b.Type, to)
|
||||
}
|
||||
|
||||
func (b *bindObject) Assign(ctx []reflect.Value, toSetter func(reflect.Value)) {
|
||||
if b.BindType == functionResultType {
|
||||
toSetter(b.ReturnValue(ctx))
|
||||
return
|
||||
}
|
||||
toSetter(b.Value)
|
||||
}
|
||||
|
||||
type (
|
||||
targetField struct {
|
||||
Object *bindObject
|
||||
FieldIndex []int
|
||||
}
|
||||
targetFuncInput struct {
|
||||
Object *bindObject
|
||||
InputIndex int
|
||||
}
|
||||
)
|
||||
|
||||
type targetStruct struct {
|
||||
Fields []*targetField
|
||||
Valid bool // is True when contains fields and it's a valid target struct.
|
||||
}
|
||||
|
||||
func newTargetStruct(v reflect.Value, bindValues ...reflect.Value) *targetStruct {
|
||||
typ := indirectTyp(v.Type())
|
||||
s := &targetStruct{}
|
||||
|
||||
fields := lookupFields(typ, nil)
|
||||
for _, f := range fields {
|
||||
// if it's context then bind it directly here and continue to the next field.
|
||||
if isContext(f.Type) {
|
||||
s.Fields = append(s.Fields, &targetField{
|
||||
FieldIndex: f.Index,
|
||||
Object: newContextBindObject(),
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
for _, val := range bindValues {
|
||||
// the binded values to the struct's fields.
|
||||
b, err := makeBindObject(val)
|
||||
|
||||
if err != nil {
|
||||
return s // if error stop here.
|
||||
}
|
||||
|
||||
if b.IsAssignable(f.Type) {
|
||||
// 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, &targetField{
|
||||
FieldIndex: f.Index,
|
||||
Object: &b,
|
||||
})
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
s.Valid = len(s.Fields) > 0
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *targetStruct) Fill(destElem reflect.Value, ctx ...reflect.Value) {
|
||||
for _, f := range s.Fields {
|
||||
f.Object.Assign(ctx, func(v reflect.Value) {
|
||||
// if isContext(v.Type()) {
|
||||
// println("WTF BIND CONTEXT TYPE WHEN BASE CONTROLLER?")
|
||||
// }
|
||||
destElem.FieldByIndex(f.FieldIndex).Set(v)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type targetFunc struct {
|
||||
Inputs []*targetFuncInput
|
||||
Valid bool // is True when contains func inputs and it's a valid target func.
|
||||
}
|
||||
|
||||
func newTargetFunc(fn reflect.Value, bindValues ...reflect.Value) *targetFunc {
|
||||
typ := indirectTyp(fn.Type())
|
||||
s := &targetFunc{
|
||||
Valid: false,
|
||||
}
|
||||
|
||||
if !isFunc(typ) {
|
||||
return s
|
||||
}
|
||||
|
||||
n := typ.NumIn()
|
||||
|
||||
// function input can have many values of the same types,
|
||||
// so keep track of them in order to not set a func input to a next bind value,
|
||||
// i.e (string, string) with two different binder funcs because of the different param's name.
|
||||
consumedValues := make(map[int]bool, n)
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
inTyp := typ.In(i)
|
||||
|
||||
// if it's context then bind it directly here and continue to the next func's input arg.
|
||||
if isContext(inTyp) {
|
||||
s.Inputs = append(s.Inputs, &targetFuncInput{
|
||||
InputIndex: i,
|
||||
Object: newContextBindObject(),
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
for valIdx, val := range bindValues {
|
||||
if _, shouldSkip := consumedValues[valIdx]; shouldSkip {
|
||||
continue
|
||||
}
|
||||
inTyp := typ.In(i)
|
||||
|
||||
// the binded values to the func's inputs.
|
||||
b, err := makeBindObject(val)
|
||||
|
||||
if err != nil {
|
||||
return s // if error stop here.
|
||||
}
|
||||
|
||||
if b.IsAssignable(inTyp) {
|
||||
// fmt.Printf("binded input index: %d for type: %s and value: %v with pointer: %v\n",
|
||||
// i, b.Type.String(), val.String(), val.Pointer())
|
||||
s.Inputs = append(s.Inputs, &targetFuncInput{
|
||||
InputIndex: i,
|
||||
Object: &b,
|
||||
})
|
||||
|
||||
consumedValues[valIdx] = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s.Valid = len(s.Inputs) > 0
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *targetFunc) Fill(in *[]reflect.Value, ctx ...reflect.Value) {
|
||||
args := *in
|
||||
for _, input := range s.Inputs {
|
||||
input.Object.Assign(ctx, func(v reflect.Value) {
|
||||
// fmt.Printf("assign input index: %d for value: %v\n",
|
||||
// input.InputIndex, v.String())
|
||||
args[input.InputIndex] = v
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
*in = args
|
||||
}
|
||||
|
|
|
@ -1,99 +0,0 @@
|
|||
package mvc2
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
/// TODO:
|
||||
// create another package because these bindings things are useful
|
||||
// for other libraries I'm working on, so something like github.com/kataras/di
|
||||
// will be great, combine these with the bind.go and controller's inside handler
|
||||
// but generic things.
|
||||
|
||||
type ValueStore []reflect.Value
|
||||
|
||||
// Bind binds values to this controller, if you want to share
|
||||
// binding values between controllers use the Engine's `Bind` function instead.
|
||||
func (bv *ValueStore) Bind(values ...interface{}) {
|
||||
for _, val := range values {
|
||||
bv.bind(reflect.ValueOf(val))
|
||||
}
|
||||
}
|
||||
|
||||
func (bv *ValueStore) bind(v reflect.Value) {
|
||||
if !goodVal(v) {
|
||||
return
|
||||
}
|
||||
|
||||
*bv = append(*bv, v)
|
||||
}
|
||||
|
||||
// Unbind unbinds a binding value based on the type,
|
||||
// it returns true if at least one field is not binded anymore.
|
||||
//
|
||||
// The "n" indicates the number of elements to remove, if <=0 then it's 1,
|
||||
// this is useful because you may have bind more than one value to two or more fields
|
||||
// with the same type.
|
||||
func (bv *ValueStore) Unbind(value interface{}, n int) bool {
|
||||
return bv.unbind(reflect.TypeOf(value), n)
|
||||
}
|
||||
|
||||
func (bv *ValueStore) unbind(typ reflect.Type, n int) (ok bool) {
|
||||
input := *bv
|
||||
for i, in := range input {
|
||||
if equalTypes(in.Type(), typ) {
|
||||
ok = true
|
||||
input = input[:i+copy(input[i:], input[i+1:])]
|
||||
if n > 1 {
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
*bv = input
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// BindExists returns true if a binder responsible to
|
||||
// bind and return a type of "typ" is already registered to this controller.
|
||||
func (bv *ValueStore) BindExists(value interface{}) bool {
|
||||
return bv.bindTypeExists(reflect.TypeOf(value))
|
||||
}
|
||||
|
||||
func (bv *ValueStore) bindTypeExists(typ reflect.Type) bool {
|
||||
input := *bv
|
||||
for _, in := range input {
|
||||
if equalTypes(in.Type(), typ) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// BindIfNotExists bind a value to the controller's field with the same type,
|
||||
// if it's not binded already.
|
||||
//
|
||||
// Returns false if binded already or the value is not the proper one for binding,
|
||||
// otherwise true.
|
||||
func (bv *ValueStore) BindIfNotExists(value interface{}) bool {
|
||||
return bv.bindIfNotExists(reflect.ValueOf(value))
|
||||
}
|
||||
|
||||
func (bv *ValueStore) bindIfNotExists(v reflect.Value) bool {
|
||||
var (
|
||||
typ = v.Type() // no element, raw things here.
|
||||
)
|
||||
|
||||
if !goodVal(v) {
|
||||
return false
|
||||
}
|
||||
|
||||
if bv.bindTypeExists(typ) {
|
||||
return false
|
||||
}
|
||||
|
||||
bv.bind(v)
|
||||
return true
|
||||
}
|
|
@ -4,6 +4,8 @@ import (
|
|||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/kataras/di"
|
||||
|
||||
"github.com/kataras/iris/context"
|
||||
"github.com/kataras/iris/core/router"
|
||||
"github.com/kataras/iris/core/router/macro"
|
||||
|
@ -89,17 +91,16 @@ type ControllerActivator struct {
|
|||
// the BeginRequest, EndRequest and OnActivate are reserved by the internal implementation.
|
||||
reservedMethods []string
|
||||
|
||||
// input are always empty after the `activate`
|
||||
// are used to build the bindings, and we need this field
|
||||
// because we have 3 states (Engine.Input, OnActivate, Bind)
|
||||
// that we can add or override binding values.
|
||||
ValueStore // TODO: or ... this is dirty code I will have to re format it a bit tomorrow.
|
||||
// the bindings that comes from the Engine and the controller's filled fields if any.
|
||||
// Can be binded to the the new controller's fields and method that is fired
|
||||
// on incoming requests.
|
||||
Dependencies *di.D
|
||||
|
||||
// the bindings that comes from input (and Engine) and can be binded to the controller's(initRef) fields.
|
||||
bindings *targetStruct
|
||||
// on activate.
|
||||
injector *di.StructInjector
|
||||
}
|
||||
|
||||
func newControllerActivator(router router.Party, controller interface{}, bindValues ...reflect.Value) *ControllerActivator {
|
||||
func newControllerActivator(router router.Party, controller interface{}, d *di.D) *ControllerActivator {
|
||||
var (
|
||||
val = reflect.ValueOf(controller)
|
||||
typ = val.Type()
|
||||
|
@ -115,7 +116,7 @@ func newControllerActivator(router router.Party, controller interface{}, bindVal
|
|||
// the end-developer when declaring the controller,
|
||||
// activate listeners needs them in order to know if something set-ed already or not,
|
||||
// look `BindTypeExists`.
|
||||
bindValues = append(lookupNonZeroFieldsValues(val), bindValues...)
|
||||
d.Values = append(lookupNonZeroFieldsValues(val), d.Values...)
|
||||
|
||||
c := &ControllerActivator{
|
||||
// give access to the Router to the end-devs if they need it for some reason,
|
||||
|
@ -133,20 +134,22 @@ func newControllerActivator(router router.Party, controller interface{}, bindVal
|
|||
//
|
||||
// TODO: now that BaseController is totally optionally
|
||||
// we have to check if BeginRequest and EndRequest should be here.
|
||||
reservedMethods: []string{
|
||||
"BeginRequest",
|
||||
"EndRequest",
|
||||
"OnActivate",
|
||||
},
|
||||
// set the input as []reflect.Value in order to be able
|
||||
// to check if a bind type is already exists, or even
|
||||
// override the structBindings that are being generated later on.
|
||||
ValueStore: bindValues,
|
||||
reservedMethods: whatReservedMethods(typ),
|
||||
Dependencies: d,
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func whatReservedMethods(typ reflect.Type) []string {
|
||||
methods := []string{"OnActivate"}
|
||||
if isBaseController(typ) {
|
||||
methods = append(methods, "BeginRequest", "EndRequest")
|
||||
}
|
||||
|
||||
return methods
|
||||
}
|
||||
|
||||
// checks if a method is already registered.
|
||||
func (c *ControllerActivator) isReservedMethod(name string) bool {
|
||||
for _, s := range c.reservedMethods {
|
||||
|
@ -178,15 +181,8 @@ func (c *ControllerActivator) parseMethods() {
|
|||
}
|
||||
}
|
||||
|
||||
// SetBindings will override any bindings with the new "values".
|
||||
func (c *ControllerActivator) SetBindings(values ...reflect.Value) {
|
||||
// set field index with matching binders, if any.
|
||||
c.ValueStore = values
|
||||
c.bindings = newTargetStruct(c.Value, values...)
|
||||
}
|
||||
|
||||
func (c *ControllerActivator) activate() {
|
||||
c.SetBindings(c.ValueStore...)
|
||||
c.injector = c.Dependencies.Struct(c.Value)
|
||||
c.parseMethods()
|
||||
}
|
||||
|
||||
|
@ -236,11 +232,13 @@ func (c *ControllerActivator) Handle(method, path, funcName string, middleware .
|
|||
// end-dev's controller pointer.
|
||||
pathParams := getPathParamsForInput(tmpl.Params, funcIn[1:]...)
|
||||
// get the function's input arguments' bindings.
|
||||
funcBindings := newTargetFunc(m.Func, pathParams...)
|
||||
funcDependencies := c.Dependencies.Clone()
|
||||
funcDependencies.Add(pathParams...)
|
||||
funcInjector := funcDependencies.Func(m.Func)
|
||||
|
||||
// we will make use of 'n' to make a slice of reflect.Value
|
||||
// to pass into if the function has input arguments that
|
||||
// are will being filled by the funcBindings.
|
||||
// are will being filled by the funcDependencies.
|
||||
n := len(funcIn)
|
||||
// the element value, not the pointer, wil lbe used to create a
|
||||
// new controller on each incoming request.
|
||||
|
@ -249,19 +247,8 @@ func (c *ControllerActivator) Handle(method, path, funcName string, middleware .
|
|||
implementsBase := isBaseController(c.Type)
|
||||
|
||||
handler := func(ctx context.Context) {
|
||||
// create a new controller instance of that type(>ptr).
|
||||
ctrl := reflect.New(elemTyp)
|
||||
|
||||
// // the Interface(). is faster than MethodByName or pre-selected methods.
|
||||
// b := ctrl.Interface().(BaseController)
|
||||
// // init the request.
|
||||
// b.BeginRequest(ctx)
|
||||
|
||||
// // if begin request stopped the execution.
|
||||
// if ctx.IsStopped() {
|
||||
// return
|
||||
// }
|
||||
|
||||
if implementsBase {
|
||||
// the Interface(). is faster than MethodByName or pre-selected methods.
|
||||
b := ctrl.Interface().(BaseController)
|
||||
|
@ -273,34 +260,32 @@ func (c *ControllerActivator) Handle(method, path, funcName string, middleware .
|
|||
return
|
||||
}
|
||||
|
||||
// EndRequest will be called at any case except the `BeginRequest` is
|
||||
// stopped.
|
||||
defer b.EndRequest(ctx)
|
||||
}
|
||||
|
||||
if !c.bindings.Valid && !funcBindings.Valid {
|
||||
if !c.injector.Valid && !funcInjector.Valid {
|
||||
DispatchFuncResult(ctx, ctrl.Method(m.Index).Call(emptyIn))
|
||||
} else {
|
||||
ctxValue := reflect.ValueOf(ctx)
|
||||
if c.bindings.Valid {
|
||||
if c.injector.Valid {
|
||||
elem := ctrl.Elem()
|
||||
c.bindings.Fill(elem, ctxValue)
|
||||
c.injector.InjectElem(elem, ctxValue)
|
||||
if ctx.IsStopped() {
|
||||
return
|
||||
}
|
||||
|
||||
// we do this in order to reduce in := make...
|
||||
// if not func input binders, we execute the handler with empty input args.
|
||||
if !funcBindings.Valid {
|
||||
if !funcInjector.Valid {
|
||||
DispatchFuncResult(ctx, ctrl.Method(m.Index).Call(emptyIn))
|
||||
}
|
||||
}
|
||||
// otherwise, it has one or more valid input binders,
|
||||
// make the input and call the func using those.
|
||||
if funcBindings.Valid {
|
||||
if funcInjector.Valid {
|
||||
in := make([]reflect.Value, n, n)
|
||||
in[0] = ctrl
|
||||
funcBindings.Fill(&in, ctxValue)
|
||||
funcInjector.Inject(&in, ctxValue)
|
||||
if ctx.IsStopped() {
|
||||
return
|
||||
}
|
||||
|
@ -309,12 +294,6 @@ func (c *ControllerActivator) Handle(method, path, funcName string, middleware .
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
// if ctx.IsStopped() {
|
||||
// return
|
||||
// }
|
||||
|
||||
// b.EndRequest(ctx)
|
||||
}
|
||||
|
||||
// register the handler now.
|
||||
|
|
|
@ -421,8 +421,8 @@ type testControllerActivateListener struct {
|
|||
}
|
||||
|
||||
func (c *testControllerActivateListener) OnActivate(ca *ControllerActivator) {
|
||||
if !ca.BindExists(&testBindType{}) {
|
||||
ca.Bind(&testBindType{
|
||||
if !ca.Dependencies.BindExists(&testBindType{}) {
|
||||
ca.Dependencies.Bind(&testBindType{
|
||||
title: "default title",
|
||||
})
|
||||
}
|
||||
|
|
|
@ -2,9 +2,10 @@ package mvc2
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
|
||||
"github.com/kataras/di"
|
||||
"github.com/kataras/golog"
|
||||
|
||||
"github.com/kataras/iris/context"
|
||||
"github.com/kataras/iris/core/router"
|
||||
)
|
||||
|
@ -16,38 +17,28 @@ var (
|
|||
)
|
||||
|
||||
type Engine struct {
|
||||
Input []reflect.Value
|
||||
dependencies *di.D
|
||||
}
|
||||
|
||||
func New() *Engine {
|
||||
return new(Engine)
|
||||
return &Engine{
|
||||
dependencies: di.New().Hijack(hijacker).GoodFunc(typeChecker),
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Engine) Bind(values ...interface{}) *Engine {
|
||||
for _, val := range values {
|
||||
if v := reflect.ValueOf(val); goodVal(v) {
|
||||
e.Input = append(e.Input, v)
|
||||
}
|
||||
}
|
||||
|
||||
e.dependencies.Bind(values...)
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *Engine) Child() *Engine {
|
||||
child := New()
|
||||
|
||||
// copy the current parent's ctx func binders and services to this new child.
|
||||
if n := len(e.Input); n > 0 {
|
||||
input := make([]reflect.Value, n, n)
|
||||
copy(input, e.Input)
|
||||
child.Input = input
|
||||
}
|
||||
|
||||
child.dependencies = e.dependencies.Clone()
|
||||
return child
|
||||
}
|
||||
|
||||
func (e *Engine) Handler(handler interface{}) context.Handler {
|
||||
h, err := MakeHandler(handler, e.Input...)
|
||||
h, err := MakeHandler(handler, e.dependencies.Values...)
|
||||
if err != nil {
|
||||
golog.Errorf("mvc handler: %v", err)
|
||||
}
|
||||
|
@ -55,7 +46,7 @@ func (e *Engine) Handler(handler interface{}) context.Handler {
|
|||
}
|
||||
|
||||
func (e *Engine) Controller(router router.Party, controller interface{}, onActivate ...func(*ControllerActivator)) {
|
||||
ca := newControllerActivator(router, controller, e.Input...)
|
||||
ca := newControllerActivator(router, controller, e.dependencies)
|
||||
|
||||
// give a priority to the "onActivate"
|
||||
// callbacks, if any.
|
||||
|
|
|
@ -267,7 +267,7 @@ func (t *testControllerViewResultRespectCtxViewData) Get() Result {
|
|||
func TestControllerViewResultRespectCtxViewData(t *testing.T) {
|
||||
app := iris.New()
|
||||
New().Controller(app, new(testControllerViewResultRespectCtxViewData), func(ca *ControllerActivator) {
|
||||
ca.Bind(t)
|
||||
ca.Dependencies.Bind(t)
|
||||
})
|
||||
e := httptest.New(t, app)
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package mvc2
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/kataras/di"
|
||||
"reflect"
|
||||
"runtime"
|
||||
|
||||
|
@ -64,7 +65,7 @@ func MakeHandler(handler interface{}, bindValues ...reflect.Value) (context.Hand
|
|||
return h, nil
|
||||
}
|
||||
|
||||
s := newTargetFunc(fn, bindValues...)
|
||||
s := di.MakeFuncInjector(fn, hijacker, typeChecker, bindValues...)
|
||||
if !s.Valid {
|
||||
pc := fn.Pointer()
|
||||
fpc := runtime.FuncForPC(pc)
|
||||
|
@ -72,14 +73,14 @@ func MakeHandler(handler interface{}, bindValues ...reflect.Value) (context.Hand
|
|||
callerName := fpc.Name()
|
||||
|
||||
err := fmt.Errorf("input arguments length(%d) and valid binders length(%d) are not equal for typeof '%s' which is defined at %s:%d by %s",
|
||||
n, len(s.Inputs), fn.Type().String(), callerFileName, callerLineNumber, callerName)
|
||||
n, s.Length, fn.Type().String(), callerFileName, callerLineNumber, callerName)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
h := func(ctx context.Context) {
|
||||
in := make([]reflect.Value, n, n)
|
||||
|
||||
s.Fill(&in, reflect.ValueOf(ctx))
|
||||
s.Inject(&in, reflect.ValueOf(ctx))
|
||||
if ctx.IsStopped() {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -110,6 +110,10 @@ func lookupFields(elemTyp reflect.Type, parentIndex []int) (fields []field) {
|
|||
for i, n := 0, elemTyp.NumField(); i < n; i++ {
|
||||
f := elemTyp.Field(i)
|
||||
|
||||
if f.PkgPath != "" {
|
||||
continue // skip unexported.
|
||||
}
|
||||
|
||||
if indirectTyp(f.Type).Kind() == reflect.Struct &&
|
||||
!structFieldIgnored(f) {
|
||||
fields = append(fields, lookupFields(f.Type, append(parentIndex, i))...)
|
||||
|
|
|
@ -22,7 +22,7 @@ type SessionController struct {
|
|||
// It makes sure that its "Manager" field is filled
|
||||
// even if the caller didn't provide any sessions manager via the `app.Controller` function.
|
||||
func (s *SessionController) OnActivate(ca *ControllerActivator) {
|
||||
if didntBindManually := ca.BindIfNotExists(defaultSessionManager); didntBindManually {
|
||||
if didntBindManually := ca.Dependencies.BindIfNotExists(defaultSessionManager); didntBindManually {
|
||||
ca.Router.GetReporter().Add(
|
||||
`MVC SessionController: couldn't find any "*sessions.Sessions" bindable value to fill the "Manager" field,
|
||||
therefore this controller is using the default sessions manager instead.
|
||||
|
|
Loading…
Reference in New Issue
Block a user