60
60
_ AfterActivation = (* ControllerActivator )(nil )
61
61
)
62
62
63
+ // IgnoreEmbeddedControllers is a global variable which indicates whether
64
+ // the controller's method parser should skip converting embedded struct's methods to http handlers.
65
+ //
66
+ // If no global use is necessary, developers can do the same for individual controllers
67
+ // through the `IgnoreEmbedded` Controller Option on `mvc.Application.Handle` method.
68
+ //
69
+ // Defaults to false.
70
+ var IgnoreEmbeddedControllers = false
71
+
63
72
// ControllerActivator returns a new controller type info description.
64
73
// Its functionality can be overridden by the end-dev.
65
74
type ControllerActivator struct {
@@ -78,6 +87,8 @@ type ControllerActivator struct {
78
87
// End-devs can change some properties of the *Route on the `BeforeActivator` by using the
79
88
// `GetRoute/GetRoutes(functionName)`.
80
89
routes map [string ][]* router.Route
90
+
91
+ skipMethodNames []string
81
92
// BeginHandlers is a slice of middleware for this controller.
82
93
// These handlers will be prependend to each one of
83
94
// the route that this controller will register(Handle/HandleMany/struct methods)
@@ -114,7 +125,6 @@ func newControllerActivator(app *Application, controller interface{}) *Controlle
114
125
}
115
126
116
127
typ := reflect .TypeOf (controller )
117
-
118
128
c := & ControllerActivator {
119
129
// give access to the Router to the end-devs if they need it for some reason,
120
130
// i.e register done handlers.
@@ -132,6 +142,10 @@ func newControllerActivator(app *Application, controller interface{}) *Controlle
132
142
routes : whatReservedMethods (typ ),
133
143
}
134
144
145
+ if IgnoreEmbeddedControllers {
146
+ c .SkipEmbeddedMethods ()
147
+ }
148
+
135
149
return c
136
150
}
137
151
@@ -157,6 +171,43 @@ func whatReservedMethods(typ reflect.Type) map[string][]*router.Route {
157
171
return routes
158
172
}
159
173
174
+ func whatEmbeddedMethods (typ reflect.Type ) []string {
175
+ var embeddedMethodsToIgnore []string
176
+ controllerType := typ
177
+ if controllerType .Kind () == reflect .Ptr {
178
+ controllerType = controllerType .Elem ()
179
+ }
180
+
181
+ for i := 0 ; i < controllerType .NumField (); i ++ {
182
+ structField := controllerType .Field (i )
183
+ structType := structField .Type
184
+
185
+ if ! structField .Anonymous {
186
+ continue
187
+ }
188
+
189
+ // var structValuePtr reflect.Value
190
+
191
+ if structType .Kind () == reflect .Ptr {
192
+ // keep both ptr and value instances of the struct so we can ignore all of its methods.
193
+ structType = structType .Elem ()
194
+ // structValuePtr = reflect.ValueOf(reflect.ValueOf(controller).Field(i))
195
+ }
196
+
197
+ if structType .Kind () != reflect .Struct {
198
+ continue
199
+ }
200
+
201
+ newEmbeddedStructType := reflect .New (structField .Type ).Type ()
202
+ // let's take its methods and add to methods to ignore from the parent, the controller itself.
203
+ for j := 0 ; j < newEmbeddedStructType .NumMethod (); j ++ {
204
+ embeddedMethodName := newEmbeddedStructType .Method (j ).Name
205
+ embeddedMethodsToIgnore = append (embeddedMethodsToIgnore , embeddedMethodName )
206
+ }
207
+ }
208
+ return embeddedMethodsToIgnore
209
+ }
210
+
160
211
// Name returns the full name of the controller, its package name + the type name.
161
212
// Can used at both `BeforeActivation` and `AfterActivation`.
162
213
func (c * ControllerActivator ) Name () string {
@@ -168,6 +219,20 @@ func (c *ControllerActivator) RelName() string {
168
219
return strings .TrimPrefix (c .fullName , "main." )
169
220
}
170
221
222
+ // SkipMethods can be used to individually skip one or more controller's method handlers.
223
+ func (c * ControllerActivator ) SkipMethods (methodNames ... string ) {
224
+ c .skipMethodNames = append (c .skipMethodNames , methodNames ... )
225
+ }
226
+
227
+ // SkipEmbeddedMethods should be ran before controller parsing.
228
+ // It skips all embedded struct's methods conversation to http handlers.
229
+ //
230
+ // See https://github.com/kataras/iris/issues/2103 for more.
231
+ func (c * ControllerActivator ) SkipEmbeddedMethods () {
232
+ methodsToIgnore := whatEmbeddedMethods (c .Type )
233
+ c .SkipMethods (methodsToIgnore ... )
234
+ }
235
+
171
236
// Router is the standard Iris router's public API.
172
237
// With this you can register middleware, view layouts, subdomains, serve static files
173
238
// and even add custom standard iris handlers as normally.
@@ -259,6 +324,12 @@ func (c *ControllerActivator) isReservedMethod(name string) bool {
259
324
}
260
325
}
261
326
327
+ for _ , methodName := range c .skipMethodNames {
328
+ if methodName == name {
329
+ return true
330
+ }
331
+ }
332
+
262
333
return false
263
334
}
264
335
0 commit comments