2017-08-18 16:09:18 +02:00
|
|
|
package activator
|
|
|
|
|
|
|
|
import (
|
|
|
|
"reflect"
|
2017-08-22 12:00:24 +02:00
|
|
|
|
2017-08-27 17:46:04 +02:00
|
|
|
"github.com/kataras/iris/mvc/activator/field"
|
|
|
|
|
2017-08-22 12:00:24 +02:00
|
|
|
"github.com/kataras/iris/context"
|
2017-08-18 16:09:18 +02:00
|
|
|
)
|
|
|
|
|
2017-11-27 20:39:57 +01:00
|
|
|
// binder accepts a value of something
|
|
|
|
// and tries to find its equalivent type
|
|
|
|
// inside the controller and sets that to it,
|
|
|
|
// after that each new instance of the controller will have
|
|
|
|
// this value on the specific field, like persistence data control does.
|
|
|
|
|
2017-08-18 16:09:18 +02:00
|
|
|
type binder struct {
|
2017-11-27 20:39:57 +01:00
|
|
|
elemType reflect.Type
|
|
|
|
// values and fields are matched on the `match`.
|
2017-08-18 16:09:18 +02:00
|
|
|
values []interface{}
|
2017-08-27 17:46:04 +02:00
|
|
|
fields []field.Field
|
2017-08-22 12:00:24 +02:00
|
|
|
|
|
|
|
// saves any middleware that may need to be passed to the router,
|
|
|
|
// statically, to gain performance.
|
|
|
|
middleware context.Handlers
|
2017-08-18 16:09:18 +02:00
|
|
|
}
|
|
|
|
|
2017-11-27 20:39:57 +01:00
|
|
|
func (b *binder) bind(value interface{}) {
|
|
|
|
if value == nil {
|
|
|
|
return
|
2017-08-18 16:09:18 +02:00
|
|
|
}
|
|
|
|
|
2017-11-27 20:39:57 +01:00
|
|
|
b.values = append(b.values, value) // keep values.
|
|
|
|
|
|
|
|
b.match(value)
|
|
|
|
}
|
2017-08-18 16:09:18 +02:00
|
|
|
|
2017-11-27 20:39:57 +01:00
|
|
|
func (b *binder) isEmpty() bool {
|
2017-08-18 16:09:18 +02:00
|
|
|
// if nothing valid found return nil, so the caller
|
|
|
|
// can omit the binder.
|
2017-08-22 12:00:24 +02:00
|
|
|
if len(b.fields) == 0 && len(b.middleware) == 0 {
|
2017-11-27 20:39:57 +01:00
|
|
|
return true
|
2017-08-18 16:09:18 +02:00
|
|
|
}
|
|
|
|
|
2017-11-27 20:39:57 +01:00
|
|
|
return false
|
2017-08-18 16:09:18 +02:00
|
|
|
}
|
|
|
|
|
2017-08-22 12:00:24 +02:00
|
|
|
func (b *binder) storeValueIfMiddleware(value reflect.Value) bool {
|
|
|
|
if value.CanInterface() {
|
|
|
|
if m, ok := value.Interface().(context.Handler); ok {
|
|
|
|
b.middleware = append(b.middleware, m)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
if m, ok := value.Interface().(func(context.Context)); ok {
|
|
|
|
b.middleware = append(b.middleware, m)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2017-11-27 20:39:57 +01:00
|
|
|
func (b *binder) match(v interface{}) {
|
|
|
|
value := reflect.ValueOf(v)
|
|
|
|
// handlers will be recognised as middleware, not struct fields.
|
|
|
|
// End-Developer has the option to call any handler inside
|
|
|
|
// the controller's `BeginRequest` and `EndRequest`, the
|
|
|
|
// state is respected from the method handler already.
|
|
|
|
if b.storeValueIfMiddleware(value) {
|
|
|
|
// stored as middleware, continue to the next field, we don't have
|
|
|
|
// to bind anything here.
|
|
|
|
return
|
|
|
|
}
|
2017-08-18 16:09:18 +02:00
|
|
|
|
2017-11-27 20:39:57 +01:00
|
|
|
matcher := func(elemField reflect.StructField) bool {
|
|
|
|
// If the controller's field is interface then check
|
|
|
|
// if the given binded value implements that interface.
|
|
|
|
// i.e MovieController { Service services.MovieService /* interface */ }
|
|
|
|
// app.Controller("/", new(MovieController),
|
|
|
|
// services.NewMovieMemoryService(...))
|
|
|
|
//
|
|
|
|
// `services.NewMovieMemoryService` returns a `*MovieMemoryService`
|
|
|
|
// that implements the `MovieService` interface.
|
|
|
|
if elemField.Type.Kind() == reflect.Interface {
|
|
|
|
return value.Type().Implements(elemField.Type)
|
2017-08-18 16:09:18 +02:00
|
|
|
}
|
2017-11-27 20:39:57 +01:00
|
|
|
return elemField.Type == value.Type()
|
|
|
|
}
|
2017-08-18 16:09:18 +02:00
|
|
|
|
2017-11-27 20:39:57 +01:00
|
|
|
handler := func(f *field.Field) {
|
|
|
|
f.Value = value
|
2017-08-18 16:09:18 +02:00
|
|
|
}
|
2017-11-27 20:39:57 +01:00
|
|
|
|
|
|
|
b.fields = append(b.fields, field.LookupFields(b.elemType, matcher, handler)...)
|
2017-08-18 16:09:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (b *binder) handle(c reflect.Value) {
|
2017-08-22 12:00:24 +02:00
|
|
|
// we could make check for middlewares here but
|
|
|
|
// these could easly be used outside of the controller
|
|
|
|
// so we don't have to initialize a controller to call them
|
|
|
|
// so they don't belong actually here, we will register them to the
|
|
|
|
// router itself, before the controller's handler to gain performance,
|
|
|
|
// look `activator.go#RegisterMethodHandlers` for more.
|
|
|
|
|
2017-08-18 16:09:18 +02:00
|
|
|
elem := c.Elem() // controller should always be a pointer at this state
|
|
|
|
for _, f := range b.fields {
|
2017-08-27 17:46:04 +02:00
|
|
|
f.SendTo(elem)
|
2017-08-18 16:09:18 +02:00
|
|
|
}
|
|
|
|
}
|