mirror of
https://github.com/kataras/iris.git
synced 2025-12-18 02:17:05 +00:00
New mvc.IgnoreEmbedded option to solve #2103
This commit is contained in:
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user