mirror of
https://github.com/kataras/iris.git
synced 2025-02-11 11:36:19 +01:00
08403f0317
Former-commit-id: d3d30cb15537146e3071731be9d674a5cb59de97
212 lines
6.2 KiB
Go
212 lines
6.2 KiB
Go
// Package di provides dependency injection for the Iris Hero and Iris MVC new features.
|
|
// It's used internally by "hero" and "mvc" packages.
|
|
package di
|
|
|
|
import (
|
|
"reflect"
|
|
|
|
"github.com/kataras/iris/v12/context"
|
|
)
|
|
|
|
type (
|
|
// ErrorHandler is the optional interface to handle errors per hero func,
|
|
// see `mvc/Application#HandleError` for MVC application-level error handler registration too.
|
|
//
|
|
// Handles non-nil errors return from a hero handler or a controller's method (see `DispatchFuncResult`)
|
|
// and (from v12.1.8) the error may return from a request-scoped dynamic dependency (see `MakeReturnValue`).
|
|
ErrorHandler interface {
|
|
HandleError(ctx context.Context, err error)
|
|
}
|
|
|
|
// ErrorHandlerFunc implements the `ErrorHandler`.
|
|
// It describes the type defnition for an error handler.
|
|
ErrorHandlerFunc func(ctx context.Context, err error)
|
|
)
|
|
|
|
// HandleError fires when the `DispatchFuncResult` or `MakereturnValue` return a non-nil error.
|
|
func (fn ErrorHandlerFunc) HandleError(ctx context.Context, err error) {
|
|
fn(ctx, err)
|
|
}
|
|
|
|
// DefaultErrorHandler is the default error handler will be fired on
|
|
// any error from registering a request-scoped dynamic dependency and on a controller's method failure.
|
|
var DefaultErrorHandler ErrorHandler = ErrorHandlerFunc(func(ctx context.Context, err error) {
|
|
if err == nil {
|
|
return
|
|
}
|
|
|
|
ctx.StatusCode(400)
|
|
ctx.WriteString(err.Error())
|
|
ctx.StopExecution()
|
|
})
|
|
|
|
var emptyValue reflect.Value
|
|
|
|
// DefaultFallbackBinder used to bind any oprhan inputs. Its error is handled by the `ErrorHandler`.
|
|
var DefaultFallbackBinder FallbackBinder = func(ctx context.Context, input OrphanInput) (newValue reflect.Value, err error) {
|
|
wasPtr := input.Type.Kind() == reflect.Ptr
|
|
|
|
newValue = reflect.New(IndirectType(input.Type))
|
|
ptr := newValue.Interface()
|
|
|
|
switch ctx.GetContentTypeRequested() {
|
|
case context.ContentXMLHeaderValue:
|
|
err = ctx.ReadXML(ptr)
|
|
case context.ContentYAMLHeaderValue:
|
|
err = ctx.ReadYAML(ptr)
|
|
case context.ContentFormHeaderValue:
|
|
err = ctx.ReadQuery(ptr)
|
|
case context.ContentFormMultipartHeaderValue:
|
|
err = ctx.ReadForm(ptr)
|
|
default:
|
|
err = ctx.ReadJSON(ptr)
|
|
// json
|
|
}
|
|
|
|
// if err != nil {
|
|
// return emptyValue, err
|
|
// }
|
|
|
|
if !wasPtr {
|
|
newValue = newValue.Elem()
|
|
}
|
|
|
|
return newValue, err
|
|
}
|
|
|
|
// Struct is being used to return a new injector based on
|
|
// a struct value instance, if it contains fields that the types of those
|
|
// are matching with one or more of the `Values` then they are binded
|
|
// with the injector's `Inject` and `InjectElem` methods.
|
|
func Struct(s interface{}, values ...reflect.Value) *StructInjector {
|
|
if s == nil {
|
|
return &StructInjector{}
|
|
}
|
|
|
|
return MakeStructInjector(
|
|
ValueOf(s),
|
|
SortByNumMethods,
|
|
Values(values).CloneWithFieldsOf(s)...,
|
|
)
|
|
}
|
|
|
|
// Func is being used to return a new injector based on
|
|
// a function, if it contains input arguments that the types of those
|
|
// are matching with one or more of the `Values` then they are binded
|
|
// to the function's input argument when called
|
|
// with the injector's `Inject` method.
|
|
func Func(fn interface{}, values ...reflect.Value) *FuncInjector {
|
|
if fn == nil {
|
|
return &FuncInjector{}
|
|
}
|
|
|
|
return MakeFuncInjector(
|
|
ValueOf(fn),
|
|
values...,
|
|
)
|
|
}
|
|
|
|
// D is the Dependency Injection container,
|
|
// it contains the Values that can be changed before the injectors.
|
|
// `Struct` and the `Func` methods returns an injector for specific
|
|
// struct instance-value or function.
|
|
type D struct {
|
|
Values
|
|
|
|
fallbackBinder FallbackBinder
|
|
errorHandler ErrorHandler
|
|
sorter Sorter
|
|
}
|
|
|
|
// OrphanInput represents an input without registered dependency.
|
|
// Used to help the framework (or the caller) auto-resolve it by the request.
|
|
type OrphanInput struct {
|
|
// Index int // function or struct field index.
|
|
Type reflect.Type
|
|
}
|
|
|
|
// FallbackBinder represents a handler of oprhan input values, handler's input arguments or controller's fields.
|
|
type FallbackBinder func(ctx context.Context, input OrphanInput) (reflect.Value, error)
|
|
|
|
// New creates and returns a new Dependency Injection container.
|
|
// See `Values` field and `Func` and `Struct` methods for more.
|
|
func New() *D {
|
|
return &D{
|
|
errorHandler: DefaultErrorHandler,
|
|
fallbackBinder: DefaultFallbackBinder,
|
|
}
|
|
}
|
|
|
|
// FallbackBinder adds a binder which will handle any oprhan input values.
|
|
// See `FallbackBinder` type.
|
|
func (d *D) FallbackBinder(fallbackBinder FallbackBinder) *D {
|
|
d.fallbackBinder = fallbackBinder
|
|
return d
|
|
}
|
|
|
|
// ErrorHandler adds a handler which will be fired when a handler's second output argument is error and it's not nil
|
|
// or when a request-scoped dynamic function dependency's second output argument is error and it's not nil.
|
|
func (d *D) ErrorHandler(errorHandler ErrorHandler) *D {
|
|
d.errorHandler = errorHandler
|
|
return d
|
|
}
|
|
|
|
// Sort sets the fields and valid bindable values sorter for struct injection.
|
|
func (d *D) Sort(with Sorter) *D {
|
|
d.sorter = with
|
|
return d
|
|
}
|
|
|
|
// Clone returns a new Dependency Injection container, it adopts the
|
|
// parent's (current "D") hijacker, good func type checker, sorter and all dependencies values.
|
|
func (d *D) Clone() *D {
|
|
return &D{
|
|
Values: d.Values.Clone(),
|
|
fallbackBinder: d.fallbackBinder,
|
|
errorHandler: d.errorHandler,
|
|
sorter: d.sorter,
|
|
}
|
|
}
|
|
|
|
// Struct is being used to return a new injector based on
|
|
// a struct value instance, if it contains fields that the types of those
|
|
// are matching with one or more of the `Values` then they are binded
|
|
// with the injector's `Inject` and `InjectElem` methods.
|
|
func (d *D) Struct(s interface{}) *StructInjector {
|
|
if s == nil {
|
|
return &StructInjector{}
|
|
}
|
|
|
|
injector := MakeStructInjector(
|
|
ValueOf(s),
|
|
d.sorter,
|
|
d.Values.CloneWithFieldsOf(s)...,
|
|
)
|
|
|
|
injector.ErrorHandler = d.errorHandler
|
|
injector.FallbackBinder = d.fallbackBinder
|
|
|
|
return injector
|
|
}
|
|
|
|
// Func is being used to return a new injector based on
|
|
// a function, if it contains input arguments that the types of those
|
|
// are matching with one or more of the `Values` then they are binded
|
|
// to the function's input argument when called
|
|
// with the injector's `Inject` method.
|
|
func (d *D) Func(fn interface{}) *FuncInjector {
|
|
if fn == nil {
|
|
return &FuncInjector{}
|
|
}
|
|
|
|
injector := MakeFuncInjector(
|
|
ValueOf(fn),
|
|
d.Values...,
|
|
)
|
|
|
|
injector.ErrorHandler = d.errorHandler
|
|
injector.FallbackBinder = d.fallbackBinder
|
|
|
|
return injector
|
|
}
|