1
0
mirror of https://github.com/kataras/iris.git synced 2026-01-09 13:05:56 +00:00

Ability to register a view engine per group of routes or for the current a chain of handlers

Example at: https://github.com/kataras/iris/tree/master/_examples/view/context-view-engine
This commit is contained in:
Gerasimos (Makis) Maropoulos
2020-08-05 19:34:55 +03:00
parent b363492cca
commit 5d480dc801
22 changed files with 282 additions and 66 deletions

View File

@@ -51,6 +51,9 @@ type ConfigurationReadOnly interface {
GetLanguageContextKey() string
// GetVersionContextKey returns the VersionContextKey field.
GetVersionContextKey() string
// GetViewEngineContextKey returns the ViewEngineContextKey field.
GetViewEngineContextKey() string
// GetViewLayoutContextKey returns the ViewLayoutContextKey field.
GetViewLayoutContextKey() string
// GetViewDataContextKey returns the ViewDataContextKey field.

View File

@@ -2392,16 +2392,22 @@ func (ctx *Context) CompressReader(enable bool) error {
// | Rich Body Content Writers/Renderers |
// +------------------------------------------------------------+
const (
// NoLayout to disable layout for a particular template file
NoLayout = "iris.nolayout"
)
// ViewEngine registers a view engine for the current chain of handlers.
// It overrides any previously registered engines, including the application's root ones.
// Note that, because performance is everything,
// the "engine" MUST be already ready-to-use,
// meaning that its `Load` method should be called once before this method call.
//
// To register a view engine per-group of groups too see `Party.RegisterView` instead.
func (ctx *Context) ViewEngine(engine ViewEngine) {
ctx.values.Set(ctx.app.ConfigurationReadOnly().GetViewEngineContextKey(), engine)
}
// ViewLayout sets the "layout" option if and when .View
// is being called afterwards, in the same request.
// Useful when need to set or/and change a layout based on the previous handlers in the chain.
//
// Note that the 'layoutTmplFile' argument can be set to iris.NoLayout || view.NoLayout || context.NoLayout
// Note that the 'layoutTmplFile' argument can be set to iris.NoLayout
// to disable the layout for a specific view render action,
// it disables the engine's configuration's layout property.
//
@@ -2418,7 +2424,7 @@ func (ctx *Context) ViewLayout(layoutTmplFile string) {
//
// If .View's "binding" argument is not nil and it's not a type of map
// then these data are being ignored, binding has the priority, so the main route's handler can still decide.
// If binding is a map or context.Map then these data are being added to the view data
// If binding is a map or iris.Map then these data are being added to the view data
// and passed to the template.
//
// After .View, the data are not destroyed, in order to be re-used if needed (again, in the same request as everything else),
@@ -2457,7 +2463,7 @@ func (ctx *Context) ViewData(key string, value interface{}) {
// A check for nil is always a good practise if different
// kind of values or no data are registered via `ViewData`.
//
// Similarly to `viewData := ctx.Values().Get("iris.viewData")` or
// Similarly to `viewData := ctx.Values().Get("iris.view.data")` or
// `viewData := ctx.Values().Get(ctx.Application().ConfigurationReadOnly().GetViewDataContextKey())`.
func (ctx *Context) GetViewData() map[string]interface{} {
viewDataContextKey := ctx.app.ConfigurationReadOnly().GetViewDataContextKey()
@@ -2514,7 +2520,21 @@ func (ctx *Context) View(filename string, optionalViewModel ...interface{}) erro
bindingData = ctx.values.Get(cfg.GetViewDataContextKey())
}
err := ctx.app.View(ctx, filename, layout, bindingData)
if key := cfg.GetViewEngineContextKey(); key != "" {
if engineV := ctx.values.Get(key); engineV != nil {
if engine, ok := engineV.(ViewEngine); ok {
err := engine.ExecuteWriter(ctx, filename, layout, bindingData)
if err != nil {
ctx.app.Logger().Errorf("View [%v] [%T]: %v", ctx.getLogIdentifier(), engine, err)
return err
}
return nil
}
}
}
err := ctx.app.View(ctx, filename, layout, bindingData) // if failed it logs the error.
if err != nil {
ctx.StopWithStatus(http.StatusInternalServerError)
}
@@ -2522,6 +2542,16 @@ func (ctx *Context) View(filename string, optionalViewModel ...interface{}) erro
return err
}
// getLogIdentifier returns the ID, or the client remote IP address,
// useful for internal logging of context's method failure.
func (ctx *Context) getLogIdentifier() interface{} {
if id := ctx.GetID(); id != nil {
return id
}
return ctx.RemoteAddr()
}
const (
// ContentBinaryHeaderValue header value for binary data.
ContentBinaryHeaderValue = "application/octet-stream"

22
context/view.go Normal file
View File

@@ -0,0 +1,22 @@
package context
import "io"
// ViewEngine is the interface which all view engines should be implemented in order to be registered inside iris.
type ViewEngine interface {
// Load should load the templates from a physical system directory or by an embedded one (assets/go-bindata).
Load() error
// ExecuteWriter should execute a template by its filename with an optional layout and bindingData.
ExecuteWriter(w io.Writer, filename string, layout string, bindingData interface{}) error
// Ext should return the final file extension which this view engine is responsible to render.
Ext() string
}
// ViewEngineFuncer is an addition of a view engine,
// if a view engine implements that interface
// then iris can add some closed-relative iris functions
// like {{ url }}, {{ urlpath }} and {{ tr }}.
type ViewEngineFuncer interface {
// AddFunc should adds a function to the template's function map.
AddFunc(funcName string, funcBody interface{})
}