mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 02:31:04 +01:00
New mvc.IgnoreEmbedded option to solve #2103
This commit is contained in:
parent
0954986a66
commit
34387a4a5c
30
HISTORY.md
30
HISTORY.md
|
@ -23,6 +23,36 @@ Developers are not forced to upgrade if they don't really need it. Upgrade whene
|
||||||
|
|
||||||
Change applies to `master` branch.
|
Change applies to `master` branch.
|
||||||
|
|
||||||
|
- Add `mvc.IgnoreEmbedded` option to handle [#2103](https://github.com/kataras/iris/issues/2103). Example Code:
|
||||||
|
|
||||||
|
```go
|
||||||
|
func configure(m *mvc.Application) {
|
||||||
|
m.Router.Use(cacheHandler)
|
||||||
|
m.Handle(&exampleController{
|
||||||
|
timeFormat: "Mon, Jan 02 2006 15:04:05",
|
||||||
|
}, mvc.IgnoreEmbedded /* BaseController.GetDoSomething will not be parsed at all */)
|
||||||
|
}
|
||||||
|
|
||||||
|
type BaseController struct {
|
||||||
|
Ctx iris.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *BaseController) GetDoSomething(i interface{}) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type exampleController struct {
|
||||||
|
BaseController
|
||||||
|
|
||||||
|
timeFormat string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *exampleController) Get() string {
|
||||||
|
now := time.Now().Format(c.timeFormat)
|
||||||
|
return "last time executed without cache: " + now
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
- Add `LoadKV` method on `Iris.Application.I18N` instance. It should be used when no locale files are available. It loads locales via pure Go Map (or database decoded values).
|
- Add `LoadKV` method on `Iris.Application.I18N` instance. It should be used when no locale files are available. It loads locales via pure Go Map (or database decoded values).
|
||||||
|
|
||||||
- Remove [ace](https://github.com/eknkc/amber) template parser support, as it was discontinued by its author more than five years ago.
|
- Remove [ace](https://github.com/eknkc/amber) template parser support, as it was discontinued by its author more than five years ago.
|
||||||
|
|
|
@ -179,7 +179,7 @@ http://localhost:8080/books
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
[![run in the browser](https://img.shields.io/badge/Run-in%20the%20Browser-348798.svg?style=for-the-badge&logo=repl.it)](https://bit.ly/2YJeSZe)
|
[![run in the browser](https://img.shields.io/badge/Run-in%20the%20Browser-348798.svg?style=for-the-badge&logo=repl.it)](https://replit.com/@kataras/Iris-Hello-World-v1220?v=1)
|
||||||
|
|
||||||
Iris 有完整且详尽的 **[使用文档](https://www.iris-go.com/#ebookDonateForm)** ,让您可以轻松地使用此框架。
|
Iris 有完整且详尽的 **[使用文档](https://www.iris-go.com/#ebookDonateForm)** ,让您可以轻松地使用此框架。
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ func configure(m *mvc.Application) {
|
||||||
m.Router.Use(cacheHandler)
|
m.Router.Use(cacheHandler)
|
||||||
m.Handle(&exampleController{
|
m.Handle(&exampleController{
|
||||||
timeFormat: "Mon, Jan 02 2006 15:04:05",
|
timeFormat: "Mon, Jan 02 2006 15:04:05",
|
||||||
})
|
} /* ,mvc.IgnoreEmbedded --- Can be used to ignore any embedded struct method handlers */)
|
||||||
}
|
}
|
||||||
|
|
||||||
type exampleController struct {
|
type exampleController struct {
|
||||||
|
|
|
@ -60,6 +60,15 @@ var (
|
||||||
_ AfterActivation = (*ControllerActivator)(nil)
|
_ AfterActivation = (*ControllerActivator)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// IgnoreEmbeddedControllers is a global variable which indicates whether
|
||||||
|
// the controller's method parser should skip converting embedded struct's methods to http handlers.
|
||||||
|
//
|
||||||
|
// If no global use is necessary, developers can do the same for individual controllers
|
||||||
|
// through the `IgnoreEmbedded` Controller Option on `mvc.Application.Handle` method.
|
||||||
|
//
|
||||||
|
// Defaults to false.
|
||||||
|
var IgnoreEmbeddedControllers = false
|
||||||
|
|
||||||
// ControllerActivator returns a new controller type info description.
|
// ControllerActivator returns a new controller type info description.
|
||||||
// Its functionality can be overridden by the end-dev.
|
// Its functionality can be overridden by the end-dev.
|
||||||
type ControllerActivator struct {
|
type ControllerActivator struct {
|
||||||
|
@ -78,6 +87,8 @@ type ControllerActivator struct {
|
||||||
// End-devs can change some properties of the *Route on the `BeforeActivator` by using the
|
// End-devs can change some properties of the *Route on the `BeforeActivator` by using the
|
||||||
// `GetRoute/GetRoutes(functionName)`.
|
// `GetRoute/GetRoutes(functionName)`.
|
||||||
routes map[string][]*router.Route
|
routes map[string][]*router.Route
|
||||||
|
|
||||||
|
skipMethodNames []string
|
||||||
// BeginHandlers is a slice of middleware for this controller.
|
// BeginHandlers is a slice of middleware for this controller.
|
||||||
// These handlers will be prependend to each one of
|
// These handlers will be prependend to each one of
|
||||||
// the route that this controller will register(Handle/HandleMany/struct methods)
|
// the route that this controller will register(Handle/HandleMany/struct methods)
|
||||||
|
@ -114,7 +125,6 @@ func newControllerActivator(app *Application, controller interface{}) *Controlle
|
||||||
}
|
}
|
||||||
|
|
||||||
typ := reflect.TypeOf(controller)
|
typ := reflect.TypeOf(controller)
|
||||||
|
|
||||||
c := &ControllerActivator{
|
c := &ControllerActivator{
|
||||||
// give access to the Router to the end-devs if they need it for some reason,
|
// give access to the Router to the end-devs if they need it for some reason,
|
||||||
// i.e register done handlers.
|
// i.e register done handlers.
|
||||||
|
@ -132,6 +142,10 @@ func newControllerActivator(app *Application, controller interface{}) *Controlle
|
||||||
routes: whatReservedMethods(typ),
|
routes: whatReservedMethods(typ),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if IgnoreEmbeddedControllers {
|
||||||
|
c.SkipEmbeddedMethods()
|
||||||
|
}
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,6 +171,43 @@ func whatReservedMethods(typ reflect.Type) map[string][]*router.Route {
|
||||||
return routes
|
return routes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func whatEmbeddedMethods(typ reflect.Type) []string {
|
||||||
|
var embeddedMethodsToIgnore []string
|
||||||
|
controllerType := typ
|
||||||
|
if controllerType.Kind() == reflect.Ptr {
|
||||||
|
controllerType = controllerType.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < controllerType.NumField(); i++ {
|
||||||
|
structField := controllerType.Field(i)
|
||||||
|
structType := structField.Type
|
||||||
|
|
||||||
|
if !structField.Anonymous {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// var structValuePtr reflect.Value
|
||||||
|
|
||||||
|
if structType.Kind() == reflect.Ptr {
|
||||||
|
// keep both ptr and value instances of the struct so we can ignore all of its methods.
|
||||||
|
structType = structType.Elem()
|
||||||
|
// structValuePtr = reflect.ValueOf(reflect.ValueOf(controller).Field(i))
|
||||||
|
}
|
||||||
|
|
||||||
|
if structType.Kind() != reflect.Struct {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
newEmbeddedStructType := reflect.New(structField.Type).Type()
|
||||||
|
// let's take its methods and add to methods to ignore from the parent, the controller itself.
|
||||||
|
for j := 0; j < newEmbeddedStructType.NumMethod(); j++ {
|
||||||
|
embeddedMethodName := newEmbeddedStructType.Method(j).Name
|
||||||
|
embeddedMethodsToIgnore = append(embeddedMethodsToIgnore, embeddedMethodName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return embeddedMethodsToIgnore
|
||||||
|
}
|
||||||
|
|
||||||
// Name returns the full name of the controller, its package name + the type name.
|
// Name returns the full name of the controller, its package name + the type name.
|
||||||
// Can used at both `BeforeActivation` and `AfterActivation`.
|
// Can used at both `BeforeActivation` and `AfterActivation`.
|
||||||
func (c *ControllerActivator) Name() string {
|
func (c *ControllerActivator) Name() string {
|
||||||
|
@ -168,6 +219,20 @@ func (c *ControllerActivator) RelName() string {
|
||||||
return strings.TrimPrefix(c.fullName, "main.")
|
return strings.TrimPrefix(c.fullName, "main.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SkipMethods can be used to individually skip one or more controller's method handlers.
|
||||||
|
func (c *ControllerActivator) SkipMethods(methodNames ...string) {
|
||||||
|
c.skipMethodNames = append(c.skipMethodNames, methodNames...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SkipEmbeddedMethods should be ran before controller parsing.
|
||||||
|
// It skips all embedded struct's methods conversation to http handlers.
|
||||||
|
//
|
||||||
|
// See https://github.com/kataras/iris/issues/2103 for more.
|
||||||
|
func (c *ControllerActivator) SkipEmbeddedMethods() {
|
||||||
|
methodsToIgnore := whatEmbeddedMethods(c.Type)
|
||||||
|
c.SkipMethods(methodsToIgnore...)
|
||||||
|
}
|
||||||
|
|
||||||
// Router is the standard Iris router's public API.
|
// Router is the standard Iris router's public API.
|
||||||
// With this you can register middleware, view layouts, subdomains, serve static files
|
// With this you can register middleware, view layouts, subdomains, serve static files
|
||||||
// and even add custom standard iris handlers as normally.
|
// and even add custom standard iris handlers as normally.
|
||||||
|
@ -259,6 +324,12 @@ func (c *ControllerActivator) isReservedMethod(name string) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, methodName := range c.skipMethodNames {
|
||||||
|
if methodName == name {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,13 @@ func newMethodLexer(s string) *methodLexer {
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
var allowedCapitalWords = map[string]struct{}{
|
||||||
|
"ID": {},
|
||||||
|
"JSON": {},
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
func (l *methodLexer) reset(s string) {
|
func (l *methodLexer) reset(s string) {
|
||||||
l.cur = -1
|
l.cur = -1
|
||||||
var words []string
|
var words []string
|
||||||
|
@ -36,14 +43,31 @@ func (l *methodLexer) reset(s string) {
|
||||||
end := len(s)
|
end := len(s)
|
||||||
start := -1
|
start := -1
|
||||||
|
|
||||||
|
// outter:
|
||||||
for i, n := 0, end; i < n; i++ {
|
for i, n := 0, end; i < n; i++ {
|
||||||
c := rune(s[i])
|
c := rune(s[i])
|
||||||
if unicode.IsUpper(c) {
|
if unicode.IsUpper(c) {
|
||||||
// it doesn't count the last uppercase
|
// it doesn't count the last uppercase
|
||||||
if start != -1 {
|
if start != -1 {
|
||||||
|
/*
|
||||||
|
for allowedCapitalWord := range allowedCapitalWords {
|
||||||
|
capitalWordEnd := i + len(allowedCapitalWord) // takes last char too, e.g. ReadJSON, we need the JSON.
|
||||||
|
if len(s) >= capitalWordEnd {
|
||||||
|
word := s[i:capitalWordEnd]
|
||||||
|
if word == allowedCapitalWord {
|
||||||
|
words = append(words, word)
|
||||||
|
i = capitalWordEnd
|
||||||
|
start = i
|
||||||
|
continue outter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
end = i
|
end = i
|
||||||
words = append(words, s[start:end])
|
words = append(words, s[start:end])
|
||||||
}
|
}
|
||||||
|
|
||||||
start = i
|
start = i
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -196,6 +196,13 @@ func (opt OptionFunc) Apply(c *ControllerActivator) {
|
||||||
opt(c)
|
opt(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IgnoreEmbedded is an Option which can be used to ignore all embedded struct's method handlers.
|
||||||
|
//
|
||||||
|
// For global affect, set the `IgnoreEmbeddedControllers` package-level variable to true.
|
||||||
|
var IgnoreEmbedded OptionFunc = func(c *ControllerActivator) {
|
||||||
|
c.SkipEmbeddedMethods()
|
||||||
|
}
|
||||||
|
|
||||||
// Handle serves a controller for the current mvc application's Router.
|
// Handle serves a controller for the current mvc application's Router.
|
||||||
// It accept any custom struct which its functions will be transformed
|
// It accept any custom struct which its functions will be transformed
|
||||||
// to routes.
|
// to routes.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user