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.
|
||||
|
||||
- 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).
|
||||
|
||||
- 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>
|
||||
|
||||
[![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)** ,让您可以轻松地使用此框架。
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ func configure(m *mvc.Application) {
|
|||
m.Router.Use(cacheHandler)
|
||||
m.Handle(&exampleController{
|
||||
timeFormat: "Mon, Jan 02 2006 15:04:05",
|
||||
})
|
||||
} /* ,mvc.IgnoreEmbedded --- Can be used to ignore any embedded struct method handlers */)
|
||||
}
|
||||
|
||||
type exampleController struct {
|
||||
|
|
|
@ -60,6 +60,15 @@ var (
|
|||
_ 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.
|
||||
// Its functionality can be overridden by the end-dev.
|
||||
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
|
||||
// `GetRoute/GetRoutes(functionName)`.
|
||||
routes map[string][]*router.Route
|
||||
|
||||
skipMethodNames []string
|
||||
// BeginHandlers is a slice of middleware for this controller.
|
||||
// These handlers will be prependend to each one of
|
||||
// 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)
|
||||
|
||||
c := &ControllerActivator{
|
||||
// give access to the Router to the end-devs if they need it for some reason,
|
||||
// i.e register done handlers.
|
||||
|
@ -132,6 +142,10 @@ func newControllerActivator(app *Application, controller interface{}) *Controlle
|
|||
routes: whatReservedMethods(typ),
|
||||
}
|
||||
|
||||
if IgnoreEmbeddedControllers {
|
||||
c.SkipEmbeddedMethods()
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
|
@ -157,6 +171,43 @@ func whatReservedMethods(typ reflect.Type) map[string][]*router.Route {
|
|||
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.
|
||||
// Can used at both `BeforeActivation` and `AfterActivation`.
|
||||
func (c *ControllerActivator) Name() string {
|
||||
|
@ -168,6 +219,20 @@ func (c *ControllerActivator) RelName() string {
|
|||
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.
|
||||
// With this you can register middleware, view layouts, subdomains, serve static files
|
||||
// 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
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,13 @@ func newMethodLexer(s string) *methodLexer {
|
|||
return l
|
||||
}
|
||||
|
||||
/*
|
||||
var allowedCapitalWords = map[string]struct{}{
|
||||
"ID": {},
|
||||
"JSON": {},
|
||||
}
|
||||
*/
|
||||
|
||||
func (l *methodLexer) reset(s string) {
|
||||
l.cur = -1
|
||||
var words []string
|
||||
|
@ -36,14 +43,31 @@ func (l *methodLexer) reset(s string) {
|
|||
end := len(s)
|
||||
start := -1
|
||||
|
||||
// outter:
|
||||
for i, n := 0, end; i < n; i++ {
|
||||
c := rune(s[i])
|
||||
if unicode.IsUpper(c) {
|
||||
// it doesn't count the last uppercase
|
||||
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
|
||||
words = append(words, s[start:end])
|
||||
}
|
||||
|
||||
start = i
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -196,6 +196,13 @@ func (opt OptionFunc) Apply(c *ControllerActivator) {
|
|||
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.
|
||||
// It accept any custom struct which its functions will be transformed
|
||||
// to routes.
|
||||
|
|
Loading…
Reference in New Issue
Block a user