1
0
mirror of https://github.com/kataras/iris.git synced 2025-12-19 02:47:04 +00:00

Update to 8.2.5 | Say Hello to Controllers. Read HISTORY.md

Former-commit-id: 70f8619440497d132362da86c5187bcc57f8687b
This commit is contained in:
kataras
2017-08-13 21:58:34 +03:00
parent 2786ca1960
commit 8cd07719a6
32 changed files with 1302 additions and 152 deletions

View File

@@ -0,0 +1,155 @@
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()
}
}

View File

@@ -0,0 +1,12 @@
package controllers
// Index is our index example controller.
type Index struct {
Controller
}
func (c *Index) Get() {
c.Tmpl = "index.html"
c.Data["title"] = "Index page"
c.Data["message"] = "Hello world!"
}

View File

@@ -0,0 +1,57 @@
package controllers
import (
"time"
"github.com/kataras/iris/_examples/tutorial/mvc-from-scratch/persistence"
)
// User is our user example controller.
type User struct {
Controller
// All fields that are tagged with iris:"persistence"`
// are being persistence and kept between the different requests,
// meaning that these data will not be reset-ed on each new request,
// they will be the same for all requests.
CreatedAt time.Time `iris:"persistence"`
Title string `iris:"persistence"`
DB *persistence.Database `iris:"persistence"`
}
func NewUserController(db *persistence.Database) *User {
return &User{
CreatedAt: time.Now(),
Title: "User page",
DB: db,
}
}
// Get serves using the User controller when HTTP Method is "GET".
func (c *User) Get() {
c.Tmpl = "user/index.html"
c.Data["title"] = c.Title
c.Data["username"] = "kataras " + c.Params.Get("userid")
c.Data["connstring"] = c.DB.Connstring
c.Data["uptime"] = time.Now().Sub(c.CreatedAt).Seconds()
}
/* Can use more than one, the factory will make sure
that the correct http methods are being registed for this
controller, uncommend these if you want:
func (c *User) Post() {}
func (c *User) Put() {}
func (c *User) Delete() {}
func (c *User) Connect() {}
func (c *User) Head() {}
func (c *User) Patch() {}
func (c *User) Options() {}
func (c *User) Trace() {}
*/
/*
func (c *User) All() {}
// OR
func (c *User) Any() {}
*/