feature: Pass all locals to ctx.Render (#1693)

* feature: Pass all locals to ctx.Render

* add test case for render using locals

* Added option PassLocalsToViews to enable pass locals to render

The option PassLocalsToViews is set to disabled by default

* Added a check to see if the ctx bind already contains the value

* Added a test for ctx render with locals and binds.
pull/1735/head
kingdevnl 2022-01-24 08:29:46 +01:00 committed by GitHub
parent d59f1af9c8
commit 82d1039416
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 83 additions and 0 deletions

5
app.go
View File

@ -183,6 +183,11 @@ type Config struct {
// Default: "" // Default: ""
ViewsLayout string `json:"views_layout"` ViewsLayout string `json:"views_layout"`
// PassLocalsToViews Enables passing of the locals set on a fiber.Ctx to the template engine
//
// Default: false
PassLocalsToViews bool `json:"pass_locals_to_views"`
// The amount of time allowed to read the full request including body. // The amount of time allowed to read the full request including body.
// It is reset after the request handler has returned. // It is reset after the request handler has returned.
// The connection's read deadline is reset when the connection opens. // The connection's read deadline is reset when the connection opens.

20
ctx.go
View File

@ -1017,6 +1017,26 @@ func (c *Ctx) Render(name string, bind interface{}, layouts ...string) error {
buf := bytebufferpool.Get() buf := bytebufferpool.Get()
defer bytebufferpool.Put(buf) defer bytebufferpool.Put(buf)
// Check if the PassLocalsToViews option is enabled (By default it is disabled)
if c.app.config.PassLocalsToViews {
// Safely cast the bind interface to a map
bindMap, ok := bind.(Map)
// Check if the bind is a map
if ok {
// Loop through each local and set it in the map
c.fasthttp.VisitUserValues(func(key []byte, val interface{}) {
// check if bindMap doesn't contain the key
if _, ok := bindMap[string(key)]; !ok {
// Set the key and value in the bindMap
bindMap[string(key)] = val
}
})
// set the original bind to the map
bind = bindMap
}
}
if c.app.config.Views != nil { if c.app.config.Views != nil {
// Render template based on global layout if exists // Render template based on global layout if exists
if len(layouts) == 0 && c.app.config.ViewsLayout != "" { if len(layouts) == 0 && c.app.config.ViewsLayout != "" {

View File

@ -2006,6 +2006,64 @@ func Test_Ctx_Render(t *testing.T) {
err = c.Render("./.github/testdata/template-invalid.html", nil) err = c.Render("./.github/testdata/template-invalid.html", nil)
utils.AssertEqual(t, false, err == nil) utils.AssertEqual(t, false, err == nil)
} }
func Test_Ctx_RenderWithoutLocals(t *testing.T) {
t.Parallel()
app := New(Config{
PassLocalsToViews: false,
})
c := app.AcquireCtx(&fasthttp.RequestCtx{})
c.Locals("Title", "Hello, World!")
defer app.ReleaseCtx(c)
err := c.Render("./.github/testdata/template.html", Map{})
buf := bytebufferpool.Get()
_, _ = buf.WriteString("overwrite")
defer bytebufferpool.Put(buf)
utils.AssertEqual(t, nil, err)
utils.AssertEqual(t, "<h1><no value></h1>", string(c.Response().Body()))
}
func Test_Ctx_RenderWithLocals(t *testing.T) {
t.Parallel()
app := New(Config{
PassLocalsToViews: true,
})
c := app.AcquireCtx(&fasthttp.RequestCtx{})
c.Locals("Title", "Hello, World!")
defer app.ReleaseCtx(c)
err := c.Render("./.github/testdata/template.html", Map{})
buf := bytebufferpool.Get()
_, _ = buf.WriteString("overwrite")
defer bytebufferpool.Put(buf)
utils.AssertEqual(t, nil, err)
utils.AssertEqual(t, "<h1>Hello, World!</h1>", string(c.Response().Body()))
}
func Test_Ctx_RenderWithLocalsAndBinding(t *testing.T) {
t.Parallel()
app := New(Config{
PassLocalsToViews: true,
})
c := app.AcquireCtx(&fasthttp.RequestCtx{})
c.Locals("Title", "This is a test.")
defer app.ReleaseCtx(c)
err := c.Render("./.github/testdata/template.html", Map{
"Title": "Hello, World!",
})
buf := bytebufferpool.Get()
_, _ = buf.WriteString("overwrite")
defer bytebufferpool.Put(buf)
utils.AssertEqual(t, nil, err)
utils.AssertEqual(t, "<h1>Hello, World!</h1>", string(c.Response().Body()))
}
type testTemplateEngine struct { type testTemplateEngine struct {
templates *template.Template templates *template.Template