mirror of
https://github.com/kataras/iris.git
synced 2025-01-24 03:01:03 +01:00
8cd07719a6
Former-commit-id: 70f8619440497d132362da86c5187bcc57f8687b
156 lines
3.6 KiB
Go
156 lines
3.6 KiB
Go
package controllers
|
|
|
|
import (
|
|
"reflect"
|
|
"strings"
|
|
|
|
"github.com/kataras/iris"
|
|
"github.com/kataras/iris/context"
|
|
"github.com/kataras/iris/core/router"
|
|
)
|
|
|
|
type Controller struct {
|
|
// path params.
|
|
Params *context.RequestParams
|
|
|
|
// view properties.
|
|
Layout string
|
|
Tmpl string
|
|
Data map[string]interface{}
|
|
|
|
// give access to the request context itself.
|
|
Ctx context.Context
|
|
}
|
|
|
|
// all lowercase, so user can see only the fields
|
|
// that are necessary to him/her.
|
|
func (b *Controller) init(ctx context.Context) {
|
|
b.Ctx = ctx
|
|
b.Params = ctx.Params()
|
|
b.Data = make(map[string]interface{}, 0)
|
|
}
|
|
|
|
func (b *Controller) exec() {
|
|
if v := b.Tmpl; v != "" {
|
|
if l := b.Layout; l != "" {
|
|
b.Ctx.ViewLayout(l)
|
|
}
|
|
if d := b.Data; d != nil {
|
|
for key, value := range d {
|
|
b.Ctx.ViewData(key, value)
|
|
}
|
|
}
|
|
b.Ctx.View(v)
|
|
}
|
|
}
|
|
|
|
// get the field name at compile-time,
|
|
// will help us to catch any unexpected results on future versions.
|
|
var baseControllerName = reflect.TypeOf(Controller{}).Name()
|
|
|
|
func RegisterController(app *iris.Application, path string, c interface{}) {
|
|
typ := reflect.TypeOf(c)
|
|
|
|
if typ.Kind() != reflect.Ptr {
|
|
typ = reflect.PtrTo(typ)
|
|
}
|
|
|
|
elem := typ.Elem()
|
|
|
|
// check if "c" has the "Controller" typeof `Controller` field.
|
|
b, has := elem.FieldByName(baseControllerName)
|
|
if !has {
|
|
panic("controller should have a field of Controller type")
|
|
}
|
|
|
|
baseControllerFieldIndex := b.Index[0]
|
|
persistenceFields := make(map[int]reflect.Value, 0)
|
|
|
|
if numField := elem.NumField(); numField > 1 {
|
|
val := reflect.Indirect(reflect.ValueOf(c))
|
|
|
|
for i := 0; i < numField; i++ {
|
|
f := elem.Field(i)
|
|
valF := val.Field(i)
|
|
// catch persistence data by tags, i.e:
|
|
// MyData string `iris:"persistence"`
|
|
// DB *DB `iris:"persistence"`
|
|
if t, ok := f.Tag.Lookup("iris"); ok {
|
|
if t == "persistence" {
|
|
persistenceFields[i] = reflect.ValueOf(valF.Interface())
|
|
continue
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// check if has Any() or All()
|
|
// if yes, then register all http methods and
|
|
// exit.
|
|
m, has := typ.MethodByName("Any")
|
|
if !has {
|
|
m, has = typ.MethodByName("All")
|
|
}
|
|
if has {
|
|
app.Any(path,
|
|
controllerToHandler(elem, persistenceFields,
|
|
baseControllerFieldIndex, m.Index))
|
|
return
|
|
}
|
|
|
|
// else search the entire controller
|
|
// for any compatible method function
|
|
// and register that.
|
|
for _, method := range router.AllMethods {
|
|
httpMethodFuncName := strings.Title(strings.ToLower(method))
|
|
|
|
m, has := typ.MethodByName(httpMethodFuncName)
|
|
if !has {
|
|
continue
|
|
}
|
|
|
|
httpMethodIndex := m.Index
|
|
|
|
app.Handle(method, path,
|
|
controllerToHandler(elem, persistenceFields,
|
|
baseControllerFieldIndex, httpMethodIndex))
|
|
}
|
|
|
|
}
|
|
|
|
func controllerToHandler(elem reflect.Type, persistenceFields map[int]reflect.Value,
|
|
baseControllerFieldIndex, httpMethodIndex int) context.Handler {
|
|
return func(ctx context.Context) {
|
|
// create a new controller instance of that type(>ptr).
|
|
c := reflect.New(elem)
|
|
|
|
// get the responsible method.
|
|
// Remember:
|
|
// To improve the performance
|
|
// we don't compare the ctx.Method()[HTTP Method]
|
|
// to the instance's Method, each handler is registered
|
|
// to a specific http method.
|
|
methodFunc := c.Method(httpMethodIndex)
|
|
|
|
// get the Controller embedded field.
|
|
b, _ := c.Elem().Field(baseControllerFieldIndex).Addr().Interface().(*Controller)
|
|
|
|
if len(persistenceFields) > 0 {
|
|
elem := c.Elem()
|
|
for index, value := range persistenceFields {
|
|
elem.Field(index).Set(value)
|
|
}
|
|
}
|
|
|
|
// init the new controller instance.
|
|
b.init(ctx)
|
|
|
|
// execute the responsible method for that handler.
|
|
methodFunc.Interface().(func())()
|
|
|
|
// finally, execute the controller.
|
|
b.exec()
|
|
}
|
|
}
|