mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 02:31:04 +01:00
OK, my dream-idea is implemented. TODO: Some examples and doc.go is not updated yet, comments on the mvc/di subpackage, the tutorial/vuejs-todo-mvc is running but not finished yet (it's using browser's localstorage and it should be replaced by the http requests that are registered via iris mvc
Former-commit-id: 0ea7e01ce1d78bcb78b40f3b0f5c03ad7c9abaea
This commit is contained in:
parent
55dfd195e0
commit
34664aa311
|
@ -1,19 +1,8 @@
|
|||
package controllers
|
||||
|
||||
import "github.com/kataras/iris/mvc"
|
||||
|
||||
// ValuesController is the equivalent
|
||||
// `ValuesController` of the .net core 2.0 mvc application.
|
||||
type ValuesController struct {
|
||||
mvc.C
|
||||
}
|
||||
|
||||
/* on windows tests(older) the Get was:
|
||||
func (vc *ValuesController) Get() {
|
||||
// id,_ := vc.Params.GetInt("id")
|
||||
// vc.Ctx.WriteString("value")
|
||||
}
|
||||
but as Iris is always going better, now supports return values as well*/
|
||||
type ValuesController struct{}
|
||||
|
||||
// Get handles "GET" requests to "api/values/{id}".
|
||||
func (vc *ValuesController) Get() string {
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
package main
|
||||
|
||||
/// TODO: remove this on the "master" branch, or even replace it
|
||||
// with the "iris-mvc" (the new implementatioin is even faster, close to handlers version,
|
||||
// with bindings or without).
|
||||
|
||||
import (
|
||||
"github.com/kataras/iris/_benchmarks/iris-mvc2/controllers"
|
||||
|
||||
"github.com/kataras/iris"
|
||||
"github.com/kataras/iris/_benchmarks/iris-mvc/controllers"
|
||||
"github.com/kataras/iris/mvc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := iris.New()
|
||||
app.Controller("/api/values/{id}", new(controllers.ValuesController))
|
||||
|
||||
// 24 August 2017: Iris has a built'n version updater but we don't need it
|
||||
// when benchmarking...
|
||||
mvc.New(app.Party("/api/values/{id}")).Register(new(controllers.ValuesController))
|
||||
app.Run(iris.Addr(":5000"), iris.WithoutVersionChecker)
|
||||
}
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
package controllers
|
||||
|
||||
// import "github.com/kataras/iris/mvc2"
|
||||
|
||||
// ValuesController is the equivalent
|
||||
// `ValuesController` of the .net core 2.0 mvc application.
|
||||
type ValuesController struct{} //{ mvc2.C }
|
||||
|
||||
/* on windows tests(older) the Get was:
|
||||
func (vc *ValuesController) Get() {
|
||||
// id,_ := vc.Params.GetInt("id")
|
||||
// vc.Ctx.WriteString("value")
|
||||
}
|
||||
but as Iris is always going better, now supports return values as well*/
|
||||
|
||||
// Get handles "GET" requests to "api/values/{id}".
|
||||
func (vc *ValuesController) Get() string {
|
||||
return "value"
|
||||
}
|
||||
|
||||
// Put handles "PUT" requests to "api/values/{id}".
|
||||
func (vc *ValuesController) Put() {}
|
||||
|
||||
// Delete handles "DELETE" requests to "api/values/{id}".
|
||||
func (vc *ValuesController) Delete() {}
|
|
@ -1,17 +0,0 @@
|
|||
package main
|
||||
|
||||
/// TODO: remove this on the "master" branch, or even replace it
|
||||
// with the "iris-mvc" (the new implementatioin is even faster, close to handlers version,
|
||||
// with bindings or without).
|
||||
|
||||
import (
|
||||
"github.com/kataras/iris"
|
||||
"github.com/kataras/iris/_benchmarks/iris-mvc2/controllers"
|
||||
"github.com/kataras/iris/mvc2"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := iris.New()
|
||||
mvc2.New().Controller(app.Party("/api/values/{id}"), new(controllers.ValuesController))
|
||||
app.Run(iris.Addr(":5000"), iris.WithoutVersionChecker)
|
||||
}
|
|
@ -1,13 +1,10 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/kataras/iris"
|
||||
"github.com/kataras/iris/context"
|
||||
)
|
||||
import "github.com/kataras/iris"
|
||||
|
||||
func main() {
|
||||
app := iris.New()
|
||||
app.Get("/api/values/{id}", func(ctx context.Context) {
|
||||
app.Get("/api/values/{id}", func(ctx iris.Context) {
|
||||
ctx.WriteString("value")
|
||||
})
|
||||
|
||||
|
|
|
@ -3,13 +3,6 @@ package main
|
|||
import (
|
||||
"github.com/kataras/iris"
|
||||
"github.com/kataras/iris/mvc"
|
||||
// auto-completion does not working well with type aliases
|
||||
// when embedded fields.
|
||||
// We should complete a report on golang repo for that at some point.
|
||||
//
|
||||
// Therefore import the "mvc" package manually
|
||||
// here at "hello-world" so users can see that
|
||||
// import path somewhere else than the "FAQ" section.
|
||||
|
||||
"github.com/kataras/iris/middleware/logger"
|
||||
"github.com/kataras/iris/middleware/recover"
|
||||
|
@ -43,27 +36,18 @@ func main() {
|
|||
app.Use(recover.New())
|
||||
app.Use(logger.New())
|
||||
|
||||
app.Controller("/", new(ExampleController))
|
||||
// Register a controller based on the root Router, "/".
|
||||
mvc.New(app).Register(new(ExampleController))
|
||||
|
||||
// http://localhost:8080
|
||||
// http://localhost:8080/ping
|
||||
// http://localhost:8080/hello
|
||||
// http://localhost:8080/custom_path
|
||||
app.Run(iris.Addr(":8080"))
|
||||
}
|
||||
|
||||
// ExampleController serves the "/", "/ping" and "/hello".
|
||||
type ExampleController struct {
|
||||
// if you build with go1.8 you have to use the mvc package always,
|
||||
// otherwise
|
||||
// you can, optionally
|
||||
// use the type alias `iris.C`,
|
||||
// same for
|
||||
// context.Context -> iris.Context,
|
||||
// mvc.Result -> iris.Result,
|
||||
// mvc.Response -> iris.Response,
|
||||
// mvc.View -> iris.View
|
||||
mvc.C
|
||||
}
|
||||
type ExampleController struct{}
|
||||
|
||||
// Get serves
|
||||
// Method: GET
|
||||
|
@ -89,6 +73,31 @@ func (c *ExampleController) GetHello() interface{} {
|
|||
return map[string]string{"message": "Hello Iris!"}
|
||||
}
|
||||
|
||||
// BeforeActivate called once, before the controller adapted to the main application
|
||||
// and of course before the server ran.
|
||||
// After version 9 you can also add custom routes for a specific controller's methods.
|
||||
// Here you can register custom method's handlers
|
||||
// use the standard router with `ca.Router` to do something that you can do without mvc as well,
|
||||
// and add dependencies that will be binded to a controller's fields or method function's input arguments.
|
||||
func (c *ExampleController) BeforeActivate(ca *mvc.ControllerActivator) {
|
||||
anyMiddlewareHere := func(ctx iris.Context) {
|
||||
ctx.Application().Logger().Warnf("Inside /custom_path")
|
||||
ctx.Next()
|
||||
}
|
||||
ca.Handle("GET", "/custom_path", "CustomHandlerWithoutFollowingTheNamingGuide", anyMiddlewareHere)
|
||||
|
||||
// or even add a global middleware based on this controller's router,
|
||||
// which in this example is the root "/":
|
||||
// ca.Router.Use(myMiddleware)
|
||||
}
|
||||
|
||||
// CustomHandlerWithoutFollowingTheNamingGuide serves
|
||||
// Method: GET
|
||||
// Resource: http://localhost:8080/custom_path
|
||||
func (c *ExampleController) CustomHandlerWithoutFollowingTheNamingGuide() string {
|
||||
return "hello from the custom handler without following the naming guide"
|
||||
}
|
||||
|
||||
// GetUserBy serves
|
||||
// Method: GET
|
||||
// Resource: http://localhost:8080/user/{username:string}
|
||||
|
@ -121,4 +130,14 @@ func (c *ExampleController) Trace() {}
|
|||
func (c *ExampleController) All() {}
|
||||
// OR
|
||||
func (c *ExampleController) Any() {}
|
||||
|
||||
|
||||
|
||||
func (c *ExampleController) BeforeActivate(ca *mvc.ControllerActivator) {
|
||||
// 1 -> the HTTP Method
|
||||
// 2 -> the route's path
|
||||
// 3 -> this controller's method name that should be handler for that route.
|
||||
ca.Handle("GET", "/mypath/{param}", "DoIt", optionalMiddlewareHere...)
|
||||
}
|
||||
|
||||
*/
|
||||
|
|
|
@ -10,38 +10,52 @@ import (
|
|||
"github.com/kataras/iris/_examples/mvc/overview/web/middleware"
|
||||
|
||||
"github.com/kataras/iris"
|
||||
"github.com/kataras/iris/mvc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := iris.New()
|
||||
app.Logger().SetLevel("debug")
|
||||
|
||||
// Load the template files.
|
||||
app.RegisterView(iris.HTML("./web/views", ".html"))
|
||||
|
||||
// Register our controllers.
|
||||
app.Controller("/hello", new(controllers.HelloController))
|
||||
mvc.New(app.Party("/hello")).Register(new(controllers.HelloController))
|
||||
// You can also split the code you write to configure an mvc.Application
|
||||
// using the `Configure` method, as shown below.
|
||||
mvc.New(app.Party("/movies")).Configure(movies)
|
||||
|
||||
// Create our movie repository with some (memory) data from the datasource.
|
||||
repo := repositories.NewMovieRepository(datasource.Movies)
|
||||
// Create our movie service, we will bind it to the movie controller.
|
||||
movieService := services.NewMovieService(repo)
|
||||
|
||||
app.Controller("/movies", new(controllers.MovieController),
|
||||
// Bind the "movieService" to the MovieController's Service (interface) field.
|
||||
movieService,
|
||||
// Add the basic authentication(admin:password) middleware
|
||||
// for the /movies based requests.
|
||||
middleware.BasicAuth)
|
||||
|
||||
// Start the web server at localhost:8080
|
||||
// http://localhost:8080/hello
|
||||
// http://localhost:8080/hello/iris
|
||||
// http://localhost:8080/movies
|
||||
// http://localhost:8080/movies/1
|
||||
app.Run(
|
||||
// Start the web server at localhost:8080
|
||||
iris.Addr("localhost:8080"),
|
||||
// disables updates:
|
||||
iris.WithoutVersionChecker,
|
||||
// skip err server closed when CTRL/CMD+C pressed:
|
||||
iris.WithoutServerError(iris.ErrServerClosed),
|
||||
iris.WithOptimizations, // enables faster json serialization and more
|
||||
// enables faster json serialization and more:
|
||||
iris.WithOptimizations,
|
||||
)
|
||||
}
|
||||
|
||||
// note the mvc.Application, it's not iris.Application.
|
||||
func movies(app *mvc.Application) {
|
||||
// Add the basic authentication(admin:password) middleware
|
||||
// for the /movies based requests.
|
||||
app.Router.Use(middleware.BasicAuth)
|
||||
|
||||
// Create our movie repository with some (memory) data from the datasource.
|
||||
repo := repositories.NewMovieRepository(datasource.Movies)
|
||||
// Create our movie service, we will bind it to the movie app's dependencies.
|
||||
movieService := services.NewMovieService(repo)
|
||||
app.AddDependencies(movieService)
|
||||
|
||||
// Register our movies controller.
|
||||
// Note that you can register more than one controller
|
||||
// you can alos create child mvc apps using the `movies.NewChild()` if you want.
|
||||
app.Register(new(controllers.MovieController))
|
||||
}
|
||||
|
|
|
@ -10,9 +10,7 @@ import (
|
|||
|
||||
// HelloController is our sample controller
|
||||
// it handles GET: /hello and GET: /hello/{name}
|
||||
type HelloController struct {
|
||||
mvc.C
|
||||
}
|
||||
type HelloController struct{}
|
||||
|
||||
var helloView = mvc.View{
|
||||
Name: "hello/index.html",
|
||||
|
@ -32,7 +30,7 @@ func (c *HelloController) Get() mvc.Result {
|
|||
return helloView
|
||||
}
|
||||
|
||||
// you can define a standard error in order to be re-usable anywhere in your app.
|
||||
// you can define a standard error in order to re-use anywhere in your app.
|
||||
var errBadName = errors.New("bad name")
|
||||
|
||||
// you can just return it as error or even better
|
||||
|
|
|
@ -9,17 +9,10 @@ import (
|
|||
"github.com/kataras/iris/_examples/mvc/overview/services"
|
||||
|
||||
"github.com/kataras/iris"
|
||||
"github.com/kataras/iris/mvc"
|
||||
)
|
||||
|
||||
// MovieController is our /movies controller.
|
||||
type MovieController struct {
|
||||
// mvc.C is just a lightweight lightweight alternative
|
||||
// to the "mvc.Controller" controller type,
|
||||
// use it when you don't need mvc.Controller's fields
|
||||
// (you don't need those fields when you return values from the method functions).
|
||||
mvc.C
|
||||
|
||||
// Our MovieService, it's an interface which
|
||||
// is binded from the main application.
|
||||
Service services.MovieService
|
||||
|
@ -53,9 +46,9 @@ func (c *MovieController) GetBy(id int64) (movie datamodels.Movie, found bool) {
|
|||
// PutBy updates a movie.
|
||||
// Demo:
|
||||
// curl -i -X PUT -F "genre=Thriller" -F "poster=@/Users/kataras/Downloads/out.gif" http://localhost:8080/movies/1
|
||||
func (c *MovieController) PutBy(id int64) (datamodels.Movie, error) {
|
||||
func (c *MovieController) PutBy(ctx iris.Context, id int64) (datamodels.Movie, error) {
|
||||
// get the request data for poster and genre
|
||||
file, info, err := c.Ctx.FormFile("poster")
|
||||
file, info, err := ctx.FormFile("poster")
|
||||
if err != nil {
|
||||
return datamodels.Movie{}, errors.New("failed due form file 'poster' missing")
|
||||
}
|
||||
|
@ -64,7 +57,7 @@ func (c *MovieController) PutBy(id int64) (datamodels.Movie, error) {
|
|||
|
||||
// imagine that is the url of the uploaded file...
|
||||
poster := info.Filename
|
||||
genre := c.Ctx.FormValue("genre")
|
||||
genre := ctx.FormValue("genre")
|
||||
|
||||
return c.Service.UpdatePosterAndGenreByID(id, poster, genre)
|
||||
}
|
||||
|
|
1
_examples/tutorial/vuejs-todo-mvc/README.md
Normal file
1
_examples/tutorial/vuejs-todo-mvc/README.md
Normal file
|
@ -0,0 +1 @@
|
|||
# Unfinished - wait until today :)
|
|
@ -4,8 +4,9 @@ import (
|
|||
"github.com/kataras/iris/_examples/tutorial/vuejs-todo-mvc/src/todo"
|
||||
|
||||
"github.com/kataras/iris"
|
||||
mvc "github.com/kataras/iris/mvc2"
|
||||
"github.com/kataras/iris/sessions"
|
||||
|
||||
"github.com/kataras/iris/mvc"
|
||||
)
|
||||
|
||||
// TodoController is our TODO app's web controller.
|
||||
|
@ -38,10 +39,6 @@ func (c *TodoController) BeforeActivate(ca *mvc.ControllerActivator) {
|
|||
})
|
||||
|
||||
// ca.Router.Use(...).Done(...).Layout(...)
|
||||
// TODO:(?)
|
||||
// m := ca.Method("PutCompleteBy")
|
||||
// m.Route.Use(...).Done(...) <- we don't have the route here but I can find something to solve this.
|
||||
// m.Dependencies.Add(...)
|
||||
}
|
||||
|
||||
// Get handles the GET: /todo route.
|
||||
|
|
|
@ -5,8 +5,9 @@ import (
|
|||
"github.com/kataras/iris/_examples/tutorial/vuejs-todo-mvc/src/web/controllers"
|
||||
|
||||
"github.com/kataras/iris"
|
||||
mvc "github.com/kataras/iris/mvc2"
|
||||
"github.com/kataras/iris/sessions"
|
||||
|
||||
"github.com/kataras/iris/mvc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@ -22,14 +23,16 @@ func main() {
|
|||
Cookie: "_iris_session",
|
||||
})
|
||||
|
||||
m := mvc.New()
|
||||
m := mvc.New(app.Party("/todo"))
|
||||
|
||||
// any bindings here...
|
||||
m.Bind(mvc.Session(sess))
|
||||
// any dependencies bindings here...
|
||||
m.AddDependencies(
|
||||
mvc.Session(sess),
|
||||
new(todo.MemoryService),
|
||||
)
|
||||
|
||||
m.Bind(new(todo.MemoryService))
|
||||
// controllers registration here...
|
||||
m.Controller(app.Party("/todo"), new(controllers.TodoController))
|
||||
m.Register(new(controllers.TodoController))
|
||||
|
||||
// start the web server at http://localhost:8080
|
||||
app.Run(iris.Addr(":8080"), iris.WithoutVersionChecker, iris.WithOptimizations)
|
||||
|
|
4
mvc/AUTHORS
Normal file
4
mvc/AUTHORS
Normal file
|
@ -0,0 +1,4 @@
|
|||
# This is the official list of Iris MVC authors for copyright
|
||||
# purposes.
|
||||
|
||||
Gerasimos Maropoulos <kataras2006@hotmail.com>
|
27
mvc/LICENSE
Normal file
27
mvc/LICENSE
Normal file
|
@ -0,0 +1,27 @@
|
|||
Copyright (c) 2018 Gerasimos Maropoulos. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Iris nor the names of its
|
||||
contributor, Gerasimos Maropoulos, may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -1,78 +1,25 @@
|
|||
package mvc2
|
||||
package mvc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/kataras/iris/mvc2/di"
|
||||
"github.com/kataras/iris/mvc/di"
|
||||
|
||||
"github.com/kataras/iris/context"
|
||||
"github.com/kataras/iris/core/router"
|
||||
"github.com/kataras/iris/core/router/macro"
|
||||
)
|
||||
|
||||
// BaseController is the controller interface,
|
||||
// which the main request `C` will implement automatically.
|
||||
// End-dev doesn't need to have any knowledge of this if she/he doesn't want to implement
|
||||
// a new Controller type.
|
||||
// Controller looks the whole flow as one handler, so `ctx.Next`
|
||||
// inside `BeginRequest` is not be respected.
|
||||
// Alternative way to check if a middleware was procceed successfully
|
||||
// and called its `ctx.Next` is the `ctx.Proceed(handler) bool`.
|
||||
// You have to navigate to the `context/context#Proceed` function's documentation.
|
||||
// BaseController is the optional controller interface, if it's
|
||||
// completed by the end controller then the BeginRequest and EndRequest
|
||||
// are called between the controller's method responsible for the incoming request.
|
||||
type BaseController interface {
|
||||
BeginRequest(context.Context)
|
||||
EndRequest(context.Context)
|
||||
}
|
||||
|
||||
// C is the basic BaseController type that can be used as an embedded anonymous field
|
||||
// to custom end-dev controllers.
|
||||
//
|
||||
// func(c *ExampleController) Get() string |
|
||||
// (string, string) |
|
||||
// (string, int) |
|
||||
// int |
|
||||
// (int, string |
|
||||
// (string, error) |
|
||||
// bool |
|
||||
// (any, bool) |
|
||||
// error |
|
||||
// (int, error) |
|
||||
// (customStruct, error) |
|
||||
// customStruct |
|
||||
// (customStruct, int) |
|
||||
// (customStruct, string) |
|
||||
// Result or (Result, error)
|
||||
// where Get is an HTTP Method func.
|
||||
//
|
||||
// Look `core/router#APIBuilder#Controller` method too.
|
||||
//
|
||||
// It completes the `activator.BaseController` interface.
|
||||
//
|
||||
// Example at: https://github.com/kataras/iris/tree/master/_examples/mvc/overview/web/controllers.
|
||||
// Example usage at: https://github.com/kataras/iris/blob/master/mvc/method_result_test.go#L17.
|
||||
type C struct {
|
||||
// The current context.Context.
|
||||
//
|
||||
// we have to name it for two reasons:
|
||||
// 1: can't ignore these via reflection, it doesn't give an option to
|
||||
// see if the functions is derived from another type.
|
||||
// 2: end-developer may want to use some method functions
|
||||
// or any fields that could be conflict with the context's.
|
||||
Ctx context.Context
|
||||
}
|
||||
|
||||
var _ BaseController = &C{}
|
||||
|
||||
// BeginRequest does nothing anymore, is here to complet ethe `BaseController` interface.
|
||||
// BaseController is not required anymore, `Ctx` is binded automatically by the engine's
|
||||
// wrapped Handler.
|
||||
func (c *C) BeginRequest(ctx context.Context) {}
|
||||
|
||||
// EndRequest does nothing, is here to complete the `BaseController` interface.
|
||||
func (c *C) EndRequest(ctx context.Context) {}
|
||||
|
||||
// ControllerActivator returns a new controller type info description.
|
||||
// Its functionality can be overriden by the end-dev.
|
||||
type ControllerActivator struct {
|
||||
|
@ -244,7 +191,10 @@ func (c *ControllerActivator) Handle(method, path, funcName string, middleware .
|
|||
// get the function's input arguments' bindings.
|
||||
funcDependencies := c.Dependencies.Clone()
|
||||
funcDependencies.AddValue(pathParams...)
|
||||
|
||||
// fmt.Printf("for %s | values: %s\n", funcName, funcDependencies.Values)
|
||||
funcInjector := funcDependencies.Func(m.Func)
|
||||
// fmt.Printf("actual injector's inputs length: %d\n", funcInjector.Length)
|
||||
|
||||
// the element value, not the pointer, wil lbe used to create a
|
||||
// new controller on each incoming request.
|
|
@ -1,29 +1,22 @@
|
|||
package mvc2_test
|
||||
package mvc_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kataras/iris"
|
||||
"github.com/kataras/iris/context"
|
||||
"github.com/kataras/iris/httptest"
|
||||
. "github.com/kataras/iris/mvc2"
|
||||
|
||||
. "github.com/kataras/iris/mvc"
|
||||
)
|
||||
|
||||
type testControllerHandle struct {
|
||||
C
|
||||
Ctx context.Context
|
||||
Service TestService
|
||||
|
||||
reqField string
|
||||
}
|
||||
|
||||
func (c *testControllerHandle) Get() string {
|
||||
return "index"
|
||||
}
|
||||
|
||||
func (c *testControllerHandle) BeginRequest(ctx iris.Context) {
|
||||
c.C.BeginRequest(ctx)
|
||||
c.reqField = ctx.URLParam("reqfield")
|
||||
}
|
||||
|
||||
func (c *testControllerHandle) BeforeActivate(ca *ControllerActivator) { // BeforeActivate(t *mvc.TController) {
|
||||
ca.Handle("GET", "/histatic", "HiStatic")
|
||||
ca.Handle("GET", "/hiservice", "HiService")
|
||||
|
@ -31,6 +24,16 @@ func (c *testControllerHandle) BeforeActivate(ca *ControllerActivator) { // Befo
|
|||
ca.Handle("GET", "/hiparamempyinput/{ps:string}", "HiParamEmptyInputBy")
|
||||
}
|
||||
|
||||
func (c *testControllerHandle) BeginRequest(ctx iris.Context) {
|
||||
c.reqField = ctx.URLParam("reqfield")
|
||||
}
|
||||
|
||||
func (c *testControllerHandle) EndRequest(ctx iris.Context) {}
|
||||
|
||||
func (c *testControllerHandle) Get() string {
|
||||
return "index"
|
||||
}
|
||||
|
||||
func (c *testControllerHandle) HiStatic() string {
|
||||
return c.reqField
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package mvc2
|
||||
package mvc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
@ -96,20 +96,31 @@ func (l *methodLexer) peekPrev() (w string) {
|
|||
}
|
||||
|
||||
var posWords = map[int]string{
|
||||
0: "",
|
||||
1: "first",
|
||||
2: "second",
|
||||
3: "third",
|
||||
4: "forth",
|
||||
5: "five",
|
||||
6: "sixth",
|
||||
7: "seventh",
|
||||
8: "eighth",
|
||||
9: "ninth",
|
||||
0: "",
|
||||
1: "first",
|
||||
2: "second",
|
||||
3: "third",
|
||||
4: "forth",
|
||||
5: "five",
|
||||
6: "sixth",
|
||||
7: "seventh",
|
||||
8: "eighth",
|
||||
9: "ninth",
|
||||
10: "tenth",
|
||||
11: "eleventh",
|
||||
12: "twelfth",
|
||||
13: "thirteenth",
|
||||
14: "fourteenth",
|
||||
15: "fifteenth",
|
||||
16: "sixteenth",
|
||||
17: "seventeenth",
|
||||
18: "eighteenth",
|
||||
19: "nineteenth",
|
||||
20: "twentieth",
|
||||
}
|
||||
|
||||
func genParamKey(argIdx int) string {
|
||||
return "param" + posWords[argIdx] // paramfirst, paramsecond...
|
||||
return "arg" + posWords[argIdx] // argfirst, argsecond...
|
||||
}
|
||||
|
||||
type methodParser struct {
|
||||
|
@ -176,7 +187,7 @@ func (p *methodParser) parse() (method, path string, err error) {
|
|||
// continue
|
||||
// }
|
||||
|
||||
if path, err = p.parsePathParam(path, w, funcArgPos); err != nil {
|
||||
if path, funcArgPos, err = p.parsePathParam(path, w, funcArgPos); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
|
@ -184,24 +195,22 @@ func (p *methodParser) parse() (method, path string, err error) {
|
|||
}
|
||||
// static path.
|
||||
path += "/" + strings.ToLower(w)
|
||||
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (p *methodParser) parsePathParam(path string, w string, funcArgPos int) (string, error) {
|
||||
func (p *methodParser) parsePathParam(path string, w string, funcArgPos int) (string, int, error) {
|
||||
typ := p.fn.Type
|
||||
|
||||
if typ.NumIn() <= funcArgPos {
|
||||
|
||||
// By found but input arguments are not there, so act like /by path without restricts.
|
||||
path += "/" + strings.ToLower(w)
|
||||
return path, nil
|
||||
return path, funcArgPos, nil
|
||||
}
|
||||
|
||||
var (
|
||||
paramKey = genParamKey(funcArgPos) // paramfirst, paramsecond...
|
||||
paramKey = genParamKey(funcArgPos) // argfirst, argsecond...
|
||||
paramType = ast.ParamTypeString // default string
|
||||
)
|
||||
|
||||
|
@ -216,10 +225,19 @@ func (p *methodParser) parsePathParam(path string, w string, funcArgPos int) (st
|
|||
// it's not wildcard, so check base on our available macro types.
|
||||
paramType = pType
|
||||
} else {
|
||||
return "", errors.New("invalid syntax for " + p.fn.Name)
|
||||
if typ.NumIn() > funcArgPos {
|
||||
// has more input arguments but we are not in the correct
|
||||
// index now, maybe the first argument was an `iris/context.Context`
|
||||
// so retry with the "funcArgPos" incremented.
|
||||
//
|
||||
// the "funcArgPos" will be updated to the caller as well
|
||||
// because we return it as well.
|
||||
return p.parsePathParam(path, w, funcArgPos+1)
|
||||
}
|
||||
return "", 0, errors.New("invalid syntax for " + p.fn.Name)
|
||||
}
|
||||
|
||||
// /{paramfirst:path}, /{paramfirst:long}...
|
||||
// /{argfirst:path}, /{argfirst:long}...
|
||||
path += fmt.Sprintf("/{%s:%s}", paramKey, paramType.String())
|
||||
|
||||
if nextWord == "" && typ.NumIn() > funcArgPos+1 {
|
||||
|
@ -232,5 +250,5 @@ func (p *methodParser) parsePathParam(path string, w string, funcArgPos int) (st
|
|||
return p.parsePathParam(path, nextWord, funcArgPos+1)
|
||||
}
|
||||
|
||||
return path, nil
|
||||
return path, funcArgPos, nil
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// black-box testing
|
||||
package mvc2_test
|
||||
package mvc_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
@ -8,56 +8,57 @@ import (
|
|||
"github.com/kataras/iris/context"
|
||||
"github.com/kataras/iris/core/router"
|
||||
"github.com/kataras/iris/httptest"
|
||||
. "github.com/kataras/iris/mvc2"
|
||||
|
||||
. "github.com/kataras/iris/mvc"
|
||||
)
|
||||
|
||||
type testController struct {
|
||||
C
|
||||
Ctx context.Context
|
||||
}
|
||||
|
||||
var writeMethod = func(c C) {
|
||||
c.Ctx.Writef(c.Ctx.Method())
|
||||
var writeMethod = func(ctx context.Context) {
|
||||
ctx.Writef(ctx.Method())
|
||||
}
|
||||
|
||||
func (c *testController) Get() {
|
||||
writeMethod(c.C)
|
||||
writeMethod(c.Ctx)
|
||||
}
|
||||
func (c *testController) Post() {
|
||||
writeMethod(c.C)
|
||||
writeMethod(c.Ctx)
|
||||
}
|
||||
func (c *testController) Put() {
|
||||
writeMethod(c.C)
|
||||
writeMethod(c.Ctx)
|
||||
}
|
||||
func (c *testController) Delete() {
|
||||
writeMethod(c.C)
|
||||
writeMethod(c.Ctx)
|
||||
}
|
||||
func (c *testController) Connect() {
|
||||
writeMethod(c.C)
|
||||
writeMethod(c.Ctx)
|
||||
}
|
||||
func (c *testController) Head() {
|
||||
writeMethod(c.C)
|
||||
writeMethod(c.Ctx)
|
||||
}
|
||||
func (c *testController) Patch() {
|
||||
writeMethod(c.C)
|
||||
writeMethod(c.Ctx)
|
||||
}
|
||||
func (c *testController) Options() {
|
||||
writeMethod(c.C)
|
||||
writeMethod(c.Ctx)
|
||||
}
|
||||
func (c *testController) Trace() {
|
||||
writeMethod(c.C)
|
||||
writeMethod(c.Ctx)
|
||||
}
|
||||
|
||||
type (
|
||||
testControllerAll struct{ C }
|
||||
testControllerAny struct{ C } // exactly the same as All.
|
||||
testControllerAll struct{ Ctx context.Context }
|
||||
testControllerAny struct{ Ctx context.Context } // exactly the same as All.
|
||||
)
|
||||
|
||||
func (c *testControllerAll) All() {
|
||||
writeMethod(c.C)
|
||||
writeMethod(c.Ctx)
|
||||
}
|
||||
|
||||
func (c *testControllerAny) Any() {
|
||||
writeMethod(c.C)
|
||||
writeMethod(c.Ctx)
|
||||
}
|
||||
|
||||
func TestControllerMethodFuncs(t *testing.T) {
|
||||
|
@ -83,7 +84,7 @@ func TestControllerMethodFuncs(t *testing.T) {
|
|||
}
|
||||
|
||||
type testControllerBeginAndEndRequestFunc struct {
|
||||
C
|
||||
Ctx context.Context
|
||||
|
||||
Username string
|
||||
}
|
||||
|
@ -93,14 +94,12 @@ type testControllerBeginAndEndRequestFunc struct {
|
|||
// useful when more than one methods using the
|
||||
// same request values or context's function calls.
|
||||
func (c *testControllerBeginAndEndRequestFunc) BeginRequest(ctx context.Context) {
|
||||
c.C.BeginRequest(ctx)
|
||||
c.Username = ctx.Params().Get("username")
|
||||
}
|
||||
|
||||
// called after every method (Get() or Post()).
|
||||
func (c *testControllerBeginAndEndRequestFunc) EndRequest(ctx context.Context) {
|
||||
ctx.Writef("done") // append "done" to the response
|
||||
c.C.EndRequest(ctx)
|
||||
}
|
||||
|
||||
func (c *testControllerBeginAndEndRequestFunc) Get() {
|
||||
|
@ -187,7 +186,7 @@ type Model struct {
|
|||
}
|
||||
|
||||
type testControllerEndRequestAwareness struct {
|
||||
C
|
||||
Ctx context.Context
|
||||
}
|
||||
|
||||
func (c *testControllerEndRequestAwareness) Get() {
|
||||
|
@ -223,9 +222,9 @@ func writeModels(ctx context.Context, names ...string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (c *testControllerEndRequestAwareness) BeginRequest(ctx context.Context) {}
|
||||
func (c *testControllerEndRequestAwareness) EndRequest(ctx context.Context) {
|
||||
writeModels(ctx, "TestModel", "myModel")
|
||||
c.C.EndRequest(ctx)
|
||||
}
|
||||
|
||||
func TestControllerEndRequestAwareness(t *testing.T) {
|
||||
|
@ -249,7 +248,8 @@ type testBindType struct {
|
|||
}
|
||||
|
||||
type testControllerBindStruct struct {
|
||||
C
|
||||
Ctx context.Context
|
||||
|
||||
// should start with upper letter of course
|
||||
TitlePointer *testBindType // should have the value of the "myTitlePtr" on test
|
||||
TitleValue testBindType // should have the value of the "myTitleV" on test
|
||||
|
@ -320,6 +320,8 @@ func (c *testCtrl0) EndRequest(ctx context.Context) {
|
|||
}
|
||||
|
||||
type testCtrl00 struct {
|
||||
Ctx context.Context
|
||||
|
||||
testCtrl000
|
||||
}
|
||||
|
||||
|
@ -330,9 +332,9 @@ type testCtrl000 struct {
|
|||
}
|
||||
|
||||
type testCtrl0000 struct {
|
||||
C
|
||||
}
|
||||
|
||||
func (c *testCtrl0000) BeginRequest(ctx context.Context) {}
|
||||
func (c *testCtrl0000) EndRequest(ctx context.Context) {
|
||||
ctx.Writef("finish")
|
||||
}
|
||||
|
@ -354,11 +356,11 @@ func TestControllerInsideControllerRecursively(t *testing.T) {
|
|||
Status(iris.StatusOK).Body().Equal(expected)
|
||||
}
|
||||
|
||||
type testControllerRelPathFromFunc struct{ C }
|
||||
type testControllerRelPathFromFunc struct{}
|
||||
|
||||
func (c *testControllerRelPathFromFunc) BeginRequest(ctx context.Context) {}
|
||||
func (c *testControllerRelPathFromFunc) EndRequest(ctx context.Context) {
|
||||
ctx.Writef("%s:%s", ctx.Method(), ctx.Path())
|
||||
c.C.EndRequest(ctx)
|
||||
}
|
||||
|
||||
func (c *testControllerRelPathFromFunc) Get() {}
|
||||
|
@ -416,8 +418,6 @@ func TestControllerRelPathFromFunc(t *testing.T) {
|
|||
}
|
||||
|
||||
type testControllerActivateListener struct {
|
||||
C
|
||||
|
||||
TitlePointer *testBindType
|
||||
}
|
||||
|
|
@ -1,8 +1,6 @@
|
|||
package di
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
import "reflect"
|
||||
|
||||
type (
|
||||
targetFuncInput struct {
|
||||
|
@ -50,7 +48,6 @@ func MakeFuncInjector(fn reflect.Value, hijack Hijacker, goodFunc TypeChecker, v
|
|||
InputIndex: i,
|
||||
Object: b,
|
||||
})
|
||||
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
@ -69,6 +66,7 @@ func MakeFuncInjector(fn reflect.Value, hijack Hijacker, goodFunc TypeChecker, v
|
|||
}
|
||||
|
||||
if b.IsAssignable(inTyp) {
|
||||
// println(inTyp.String() + " is assignable to " + val.Type().String())
|
||||
// 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{
|
||||
|
@ -82,8 +80,9 @@ func MakeFuncInjector(fn reflect.Value, hijack Hijacker, goodFunc TypeChecker, v
|
|||
}
|
||||
}
|
||||
|
||||
s.Length = n
|
||||
s.Valid = len(s.inputs) > 0
|
||||
// s.Length = n
|
||||
s.Length = len(s.inputs)
|
||||
s.Valid = s.Length > 0
|
||||
return s
|
||||
}
|
||||
|
|
@ -1,8 +1,6 @@
|
|||
package di
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
import "reflect"
|
||||
|
||||
type Values []reflect.Value
|
||||
|
105
mvc/engine.go
Normal file
105
mvc/engine.go
Normal file
|
@ -0,0 +1,105 @@
|
|||
package mvc
|
||||
|
||||
import (
|
||||
"github.com/kataras/golog"
|
||||
"github.com/kataras/iris/mvc/di"
|
||||
|
||||
"github.com/kataras/iris/context"
|
||||
"github.com/kataras/iris/core/router"
|
||||
)
|
||||
|
||||
// Engine contains the Dependencies which will be binded
|
||||
// to the controller(s) or handler(s) that can be created
|
||||
// using the Engine's `Handler` and `Controller` methods.
|
||||
//
|
||||
// This is not exported for being used by everyone, use it only when you want
|
||||
// to share engines between multi mvc.go#Application
|
||||
// or make custom mvc handlers that can be used on the standard
|
||||
// iris' APIBuilder. The last one reason is the most useful here,
|
||||
// although end-devs can use the `MakeHandler` as well.
|
||||
//
|
||||
// For a more high-level structure please take a look at the "mvc.go#Application".
|
||||
type Engine struct {
|
||||
Dependencies *di.D
|
||||
}
|
||||
|
||||
// NewEngine returns a new engine, a container for dependencies and a factory
|
||||
// for handlers and controllers, this is used internally by the `mvc#Application` structure.
|
||||
// Please take a look at the structure's documentation for more information.
|
||||
func NewEngine() *Engine {
|
||||
return &Engine{
|
||||
Dependencies: di.New().Hijack(hijacker).GoodFunc(typeChecker),
|
||||
}
|
||||
}
|
||||
|
||||
// Clone creates and returns a new engine with the parent's(current) Dependencies.
|
||||
// It copies the current "e" dependencies and returns a new engine.
|
||||
func (e *Engine) Clone() *Engine {
|
||||
child := NewEngine()
|
||||
child.Dependencies = e.Dependencies.Clone()
|
||||
return child
|
||||
}
|
||||
|
||||
// Handler accepts a "handler" function which can accept any input arguments that match
|
||||
// with the Engine's `Dependencies` and any output result; like string, int (string,int),
|
||||
// custom structs, Result(View | Response) and anything you already know that mvc implementation supports.
|
||||
// It returns a standard `iris/context.Handler` which can be used anywhere in an Iris Application,
|
||||
// as middleware or as simple route handler or subdomain's handler.
|
||||
func (e *Engine) Handler(handler interface{}) context.Handler {
|
||||
h, err := MakeHandler(handler, e.Dependencies.Values...)
|
||||
if err != nil {
|
||||
golog.Errorf("mvc handler: %v", err)
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
// Controller accepts a sub router and registers any custom struct
|
||||
// as controller, if struct doesn't have any compatible methods
|
||||
// neither are registered via `ControllerActivator`'s `Handle` method
|
||||
// then the controller is not registered at all.
|
||||
//
|
||||
// A Controller may have one or more methods
|
||||
// that are wrapped to a handler and registered as routes before the server ran.
|
||||
// The controller's method can accept any input argument that are previously binded
|
||||
// via the dependencies or route's path accepts dynamic path parameters.
|
||||
// The controller's fields are also bindable via the dependencies, either a
|
||||
// static value (service) or a function (dynamically) which accepts a context
|
||||
// and returns a single value (this type is being used to find the relative field or method's input argument).
|
||||
//
|
||||
// func(c *ExampleController) Get() string |
|
||||
// (string, string) |
|
||||
// (string, int) |
|
||||
// int |
|
||||
// (int, string |
|
||||
// (string, error) |
|
||||
// bool |
|
||||
// (any, bool) |
|
||||
// error |
|
||||
// (int, error) |
|
||||
// (customStruct, error) |
|
||||
// customStruct |
|
||||
// (customStruct, int) |
|
||||
// (customStruct, string) |
|
||||
// Result or (Result, error)
|
||||
// where Get is an HTTP Method func.
|
||||
//
|
||||
// Examples at: https://github.com/kataras/iris/tree/master/_examples/mvc.
|
||||
func (e *Engine) Controller(router router.Party, controller interface{}, beforeActivate ...func(*ControllerActivator)) {
|
||||
ca := newControllerActivator(router, controller, e.Dependencies)
|
||||
|
||||
// give a priority to the "beforeActivate"
|
||||
// callbacks, if any.
|
||||
for _, cb := range beforeActivate {
|
||||
cb(ca)
|
||||
}
|
||||
|
||||
// check if controller has an "BeforeActivate" function
|
||||
// which accepts the controller activator and call it.
|
||||
if activateListener, ok := controller.(interface {
|
||||
BeforeActivate(*ControllerActivator)
|
||||
}); ok {
|
||||
activateListener.BeforeActivate(ca)
|
||||
}
|
||||
|
||||
ca.activate()
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
package mvc2_test
|
||||
package mvc_test
|
||||
|
||||
// black-box in combination with the handler_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/kataras/iris/mvc2"
|
||||
. "github.com/kataras/iris/mvc"
|
||||
)
|
||||
|
||||
func TestMvcEngineInAndHandler(t *testing.T) {
|
|
@ -1,11 +1,11 @@
|
|||
package mvc2
|
||||
package mvc
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/structs"
|
||||
"github.com/kataras/iris/mvc2/di"
|
||||
"github.com/kataras/iris/mvc/di"
|
||||
|
||||
"github.com/kataras/iris/context"
|
||||
)
|
|
@ -1,4 +1,4 @@
|
|||
package mvc2_test
|
||||
package mvc_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
@ -7,14 +7,15 @@ import (
|
|||
"github.com/kataras/iris"
|
||||
"github.com/kataras/iris/context"
|
||||
"github.com/kataras/iris/httptest"
|
||||
. "github.com/kataras/iris/mvc2"
|
||||
|
||||
. "github.com/kataras/iris/mvc"
|
||||
)
|
||||
|
||||
// activator/methodfunc/func_caller.go.
|
||||
// and activator/methodfunc/func_result_dispatcher.go
|
||||
|
||||
type testControllerMethodResult struct {
|
||||
C
|
||||
Ctx context.Context
|
||||
}
|
||||
|
||||
func (c *testControllerMethodResult) Get() Result {
|
||||
|
@ -105,7 +106,7 @@ func TestControllerMethodResult(t *testing.T) {
|
|||
}
|
||||
|
||||
type testControllerMethodResultTypes struct {
|
||||
C
|
||||
Ctx context.Context
|
||||
}
|
||||
|
||||
func (c *testControllerMethodResultTypes) GetText() string {
|
||||
|
@ -227,16 +228,13 @@ func TestControllerMethodResultTypes(t *testing.T) {
|
|||
|
||||
type testControllerViewResultRespectCtxViewData struct {
|
||||
T *testing.T
|
||||
C
|
||||
}
|
||||
|
||||
func (t *testControllerViewResultRespectCtxViewData) BeginRequest(ctx context.Context) {
|
||||
t.C.BeginRequest(ctx)
|
||||
ctx.ViewData("name_begin", "iris_begin")
|
||||
}
|
||||
|
||||
func (t *testControllerViewResultRespectCtxViewData) EndRequest(ctx context.Context) {
|
||||
t.C.EndRequest(ctx)
|
||||
// check if data is not overridden by return View {Data: context.Map...}
|
||||
|
||||
dataWritten := ctx.GetViewData()
|
|
@ -1,8 +1,8 @@
|
|||
package mvc2
|
||||
package mvc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/kataras/iris/mvc2/di"
|
||||
"github.com/kataras/iris/mvc/di"
|
||||
"reflect"
|
||||
"runtime"
|
||||
|
||||
|
@ -39,8 +39,8 @@ func MustMakeHandler(handler interface{}, bindValues ...reflect.Value) context.H
|
|||
return h
|
||||
}
|
||||
|
||||
// MakeHandler accepts a "handler" function which can accept any input that matches
|
||||
// with the "binders" and any output, that matches the mvc types, like string, int (string,int),
|
||||
// MakeHandler accepts a "handler" function which can accept any input arguments that match
|
||||
// with the "bindValues" types and any output result, that matches the mvc types, like string, int (string,int),
|
||||
// custom structs, Result(View | Response) and anything that you already know that mvc implementation supports,
|
||||
// and returns a low-level `context/iris.Handler` which can be used anywhere in the Iris Application,
|
||||
// as middleware or as simple route handler or party handler or subdomain handler-router.
|
|
@ -1,4 +1,4 @@
|
|||
package mvc2_test
|
||||
package mvc_test
|
||||
|
||||
// black-box
|
||||
|
||||
|
@ -9,7 +9,8 @@ import (
|
|||
|
||||
"github.com/kataras/iris"
|
||||
"github.com/kataras/iris/httptest"
|
||||
. "github.com/kataras/iris/mvc2"
|
||||
|
||||
. "github.com/kataras/iris/mvc"
|
||||
)
|
||||
|
||||
// dynamic func
|
|
@ -6,7 +6,7 @@ import (
|
|||
"github.com/kataras/iris"
|
||||
"github.com/kataras/iris/sessions"
|
||||
|
||||
mvc "github.com/kataras/iris/mvc2"
|
||||
"github.com/kataras/iris/mvc"
|
||||
)
|
||||
|
||||
func main() {
|
|
@ -1,4 +1,4 @@
|
|||
package mvc2
|
||||
package mvc
|
||||
|
||||
import "github.com/kataras/iris/core/router"
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package mvc2
|
||||
package mvc
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
@ -16,20 +16,36 @@ func getPathParamsForInput(params []macro.TemplateParam, funcIn ...reflect.Type)
|
|||
return
|
||||
}
|
||||
|
||||
funcInIdx := 0
|
||||
// it's a valid param type.
|
||||
for _, p := range params {
|
||||
in := funcIn[funcInIdx]
|
||||
paramType := p.Type
|
||||
paramName := p.Name
|
||||
// fmt.Printf("%s input arg type vs %s param type\n", in.Kind().String(), p.Type.Kind().String())
|
||||
if paramType.Assignable(in.Kind()) {
|
||||
// fmt.Printf("path_param_binder.go: bind path param func for paramName = '%s' and paramType = '%s'\n", paramName, paramType.String())
|
||||
values = append(values, makeFuncParamGetter(paramType, paramName))
|
||||
consumedParams := make(map[int]bool, 0)
|
||||
for _, in := range funcIn {
|
||||
for j, p := range params {
|
||||
if _, consumed := consumedParams[j]; consumed {
|
||||
continue
|
||||
}
|
||||
paramType := p.Type
|
||||
paramName := p.Name
|
||||
// fmt.Printf("%s input arg type vs %s param type\n", in.Kind().String(), p.Type.Kind().String())
|
||||
if paramType.Assignable(in.Kind()) {
|
||||
consumedParams[j] = true
|
||||
// fmt.Printf("path_param_binder.go: bind path param func for paramName = '%s' and paramType = '%s'\n", paramName, paramType.String())
|
||||
values = append(values, makeFuncParamGetter(paramType, paramName))
|
||||
}
|
||||
}
|
||||
|
||||
funcInIdx++
|
||||
}
|
||||
// funcInIdx := 0
|
||||
// // it's a valid param type.
|
||||
// for _, p := range params {
|
||||
// in := funcIn[funcInIdx]
|
||||
// paramType := p.Type
|
||||
// paramName := p.Name
|
||||
// // fmt.Printf("%s input arg type vs %s param type\n", in.Kind().String(), p.Type.Kind().String())
|
||||
// if paramType.Assignable(in.Kind()) {
|
||||
// // fmt.Printf("path_param_binder.go: bind path param func for paramName = '%s' and paramType = '%s'\n", paramName, paramType.String())
|
||||
// values = append(values, makeFuncParamGetter(paramType, paramName))
|
||||
// }
|
||||
|
||||
// funcInIdx++
|
||||
// }
|
||||
|
||||
return
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package mvc2
|
||||
package mvc
|
||||
|
||||
import (
|
||||
"testing"
|
54
mvc/reflect.go
Normal file
54
mvc/reflect.go
Normal file
|
@ -0,0 +1,54 @@
|
|||
package mvc
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/kataras/iris/context"
|
||||
"github.com/kataras/iris/mvc/di"
|
||||
)
|
||||
|
||||
var baseControllerTyp = reflect.TypeOf((*BaseController)(nil)).Elem()
|
||||
|
||||
func isBaseController(ctrlTyp reflect.Type) bool {
|
||||
return ctrlTyp.Implements(baseControllerTyp)
|
||||
}
|
||||
|
||||
var contextTyp = reflect.TypeOf((*context.Context)(nil)).Elem()
|
||||
|
||||
func isContext(inTyp reflect.Type) bool {
|
||||
return inTyp.Implements(contextTyp)
|
||||
}
|
||||
|
||||
func getInputArgsFromFunc(funcTyp reflect.Type) []reflect.Type {
|
||||
n := funcTyp.NumIn()
|
||||
funcIn := make([]reflect.Type, n, n)
|
||||
for i := 0; i < n; i++ {
|
||||
funcIn[i] = funcTyp.In(i)
|
||||
}
|
||||
return funcIn
|
||||
}
|
||||
|
||||
var (
|
||||
typeChecker = func(fn reflect.Type) bool {
|
||||
// valid if that single input arg is a typeof context.Context.
|
||||
return fn.NumIn() == 1 && isContext(fn.In(0))
|
||||
}
|
||||
|
||||
hijacker = func(fieldOrFuncInput reflect.Type) (*di.BindObject, bool) {
|
||||
if !isContext(fieldOrFuncInput) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// this is being used on both func injector and struct injector.
|
||||
// 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`.
|
||||
return &di.BindObject{
|
||||
Type: contextTyp,
|
||||
BindType: di.Dynamic,
|
||||
ReturnValue: func(ctxValue []reflect.Value) reflect.Value {
|
||||
return ctxValue[0]
|
||||
},
|
||||
}, true
|
||||
}
|
||||
)
|
|
@ -1,4 +1,4 @@
|
|||
package mvc2
|
||||
package mvc
|
||||
|
||||
import (
|
||||
"github.com/kataras/iris/context"
|
|
@ -1,4 +1,4 @@
|
|||
package mvc2
|
||||
package mvc
|
||||
|
||||
import (
|
||||
"github.com/kataras/iris/context"
|
||||
|
@ -11,8 +11,6 @@ var defaultSessionManager = sessions.New(sessions.Config{})
|
|||
// which requires a binded session manager in order to give
|
||||
// direct access to the current client's session via its `Session` field.
|
||||
type SessionController struct {
|
||||
C
|
||||
|
||||
Manager *sessions.Sessions
|
||||
Session *sessions.Session
|
||||
}
|
||||
|
@ -30,10 +28,8 @@ func (s *SessionController) BeforeActivate(ca *ControllerActivator) {
|
|||
}
|
||||
}
|
||||
|
||||
// BeginRequest calls the Controller's BeginRequest
|
||||
// and tries to initialize the current user's Session.
|
||||
// BeginRequest initializes the current user's Session.
|
||||
func (s *SessionController) BeginRequest(ctx context.Context) {
|
||||
s.C.BeginRequest(ctx)
|
||||
if s.Manager == nil {
|
||||
ctx.Application().Logger().Errorf(`MVC SessionController: sessions manager is nil, report this as a bug
|
||||
because the SessionController should predict this on its activation state and use a default one automatically`)
|
||||
|
@ -42,3 +38,6 @@ because the SessionController should predict this on its activation state and us
|
|||
|
||||
s.Session = s.Manager.Start(ctx)
|
||||
}
|
||||
|
||||
// EndRequest is here to complete the `BaseController`.
|
||||
func (s *SessionController) EndRequest(ctx context.Context) {}
|
34
mvc2/bind.go
34
mvc2/bind.go
|
@ -1,34 +0,0 @@
|
|||
package mvc2
|
||||
|
||||
import (
|
||||
"github.com/kataras/iris/mvc2/di"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var (
|
||||
typeChecker = func(fn reflect.Type) bool {
|
||||
// invalid if that single input arg is not a typeof context.Context.
|
||||
return isContext(fn.In(0))
|
||||
}
|
||||
|
||||
hijacker = func(fieldOrFuncInput reflect.Type) (*di.BindObject, bool) {
|
||||
if isContext(fieldOrFuncInput) {
|
||||
return newContextBindObject(), true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
)
|
||||
|
||||
// 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() *di.BindObject {
|
||||
return &di.BindObject{
|
||||
Type: contextTyp,
|
||||
BindType: di.Dynamic,
|
||||
ReturnValue: func(ctxValue []reflect.Value) reflect.Value {
|
||||
return ctxValue[0]
|
||||
},
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
package mvc2
|
||||
|
||||
import (
|
||||
"github.com/kataras/iris/mvc2/di"
|
||||
"github.com/kataras/golog"
|
||||
|
||||
"github.com/kataras/iris/context"
|
||||
"github.com/kataras/iris/core/router"
|
||||
)
|
||||
|
||||
type Engine struct {
|
||||
Dependencies *di.D
|
||||
}
|
||||
|
||||
func NewEngine() *Engine {
|
||||
return &Engine{
|
||||
Dependencies: di.New().Hijack(hijacker).GoodFunc(typeChecker),
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Engine) Clone() *Engine {
|
||||
child := NewEngine()
|
||||
child.Dependencies = e.Dependencies.Clone()
|
||||
return child
|
||||
}
|
||||
|
||||
func (e *Engine) Handler(handler interface{}) context.Handler {
|
||||
h, err := MakeHandler(handler, e.Dependencies.Values...)
|
||||
if err != nil {
|
||||
golog.Errorf("mvc handler: %v", err)
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
func (e *Engine) Controller(router router.Party, controller interface{}, beforeActivate ...func(*ControllerActivator)) {
|
||||
ca := newControllerActivator(router, controller, e.Dependencies)
|
||||
|
||||
// give a priority to the "beforeActivate"
|
||||
// callbacks, if any.
|
||||
for _, cb := range beforeActivate {
|
||||
cb(ca)
|
||||
}
|
||||
|
||||
// check if controller has an "BeforeActivate" function
|
||||
// which accepts the controller activator and call it.
|
||||
if activateListener, ok := controller.(interface {
|
||||
BeforeActivate(*ControllerActivator)
|
||||
}); ok {
|
||||
activateListener.BeforeActivate(ca)
|
||||
}
|
||||
|
||||
ca.activate()
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package mvc2
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/kataras/iris/context"
|
||||
)
|
||||
|
||||
var baseControllerTyp = reflect.TypeOf((*BaseController)(nil)).Elem()
|
||||
|
||||
func isBaseController(ctrlTyp reflect.Type) bool {
|
||||
return ctrlTyp.Implements(baseControllerTyp)
|
||||
}
|
||||
|
||||
var contextTyp = reflect.TypeOf((*context.Context)(nil)).Elem()
|
||||
|
||||
func isContext(inTyp reflect.Type) bool {
|
||||
return inTyp.Implements(contextTyp)
|
||||
}
|
||||
|
||||
func getInputArgsFromFunc(funcTyp reflect.Type) []reflect.Type {
|
||||
n := funcTyp.NumIn()
|
||||
funcIn := make([]reflect.Type, n, n)
|
||||
for i := 0; i < n; i++ {
|
||||
funcIn[i] = funcTyp.In(i)
|
||||
}
|
||||
return funcIn
|
||||
}
|
Loading…
Reference in New Issue
Block a user