Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ feature: bind support for render #1754

Merged
merged 13 commits into from Feb 12, 2022
1 change: 1 addition & 0 deletions .github/README.md
Expand Up @@ -665,3 +665,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
- [dictpool](https://github.com/savsgio/dictpool)
1 change: 1 addition & 0 deletions .github/README_ckb.md
Expand Up @@ -665,3 +665,4 @@ func main() {
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
- [dictpool](https://github.com/savsgio/dictpool)
1 change: 1 addition & 0 deletions .github/README_de.md
Expand Up @@ -635,3 +635,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
- [dictpool](https://github.com/savsgio/dictpool)
2 changes: 2 additions & 0 deletions .github/README_es.md
Expand Up @@ -635,3 +635,5 @@ Copyright (c) 2019-presente [Fenny](https://github.com/fenny) y [contribuyentes]
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
- [dictpool](https://github.com/savsgio/dictpool)

1 change: 1 addition & 0 deletions .github/README_fa.md
Expand Up @@ -794,3 +794,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
- [dictpool](https://github.com/savsgio/dictpool)
1 change: 1 addition & 0 deletions .github/README_fr.md
Expand Up @@ -637,3 +637,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
- [dictpool](https://github.com/savsgio/dictpool)
1 change: 1 addition & 0 deletions .github/README_he.md
Expand Up @@ -810,4 +810,5 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
- [dictpool](https://github.com/savsgio/dictpool)
</div>
2 changes: 2 additions & 0 deletions .github/README_id.md
Expand Up @@ -638,3 +638,5 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
- [dictpool](https://github.com/savsgio/dictpool)

1 change: 1 addition & 0 deletions .github/README_it.md
Expand Up @@ -661,3 +661,4 @@ Copyright (c) 2019-ora [Fenny](https://github.com/fenny) e [Contributors](https:
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
- [dictpool](https://github.com/savsgio/dictpool)
1 change: 1 addition & 0 deletions .github/README_ja.md
Expand Up @@ -641,3 +641,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
- [dictpool](https://github.com/savsgio/dictpool)
1 change: 1 addition & 0 deletions .github/README_ko.md
Expand Up @@ -641,3 +641,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
- [dictpool](https://github.com/savsgio/dictpool)
1 change: 1 addition & 0 deletions .github/README_nl.md
Expand Up @@ -641,3 +641,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
- [dictpool](https://github.com/savsgio/dictpool)
1 change: 1 addition & 0 deletions .github/README_pt.md
Expand Up @@ -637,3 +637,4 @@ O logo oficial foi criado por [Vic Shóstak](https://github.com/koddr) e distrib
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
- [dictpool](https://github.com/savsgio/dictpool)
1 change: 1 addition & 0 deletions .github/README_ru.md
Expand Up @@ -644,3 +644,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
- [dictpool](https://github.com/savsgio/dictpool)
1 change: 1 addition & 0 deletions .github/README_sa.md
Expand Up @@ -702,3 +702,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
- [dictpool](https://github.com/savsgio/dictpool)
1 change: 1 addition & 0 deletions .github/README_tr.md
Expand Up @@ -635,3 +635,4 @@ Telif (c) 2019-günümüz [Fenny](https://github.com/fenny) ve [Contributors](ht
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
- [dictpool](https://github.com/savsgio/dictpool)
1 change: 1 addition & 0 deletions .github/README_zh-CN.md
Expand Up @@ -637,3 +637,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
- [dictpool](https://github.com/savsgio/dictpool)
1 change: 1 addition & 0 deletions .github/README_zh-TW.md
Expand Up @@ -635,3 +635,4 @@ Fiber 是一個以贊助維生的開源專案,像是: 網域、gitbook、netli
- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE)
- [go-ole](https://github.com/go-ole/go-ole)
- [wmi](https://github.com/StackExchange/wmi)
- [dictpool](https://github.com/savsgio/dictpool)
1 change: 1 addition & 0 deletions .github/testdata/template2.html
@@ -0,0 +1 @@
<h1>{{.Title}} {{.Summary}}</h1>
63 changes: 44 additions & 19 deletions ctx.go
Expand Up @@ -24,6 +24,7 @@ import (
"time"

"github.com/gofiber/fiber/v2/internal/bytebufferpool"
"github.com/gofiber/fiber/v2/internal/dictpool"
"github.com/gofiber/fiber/v2/internal/go-json"
"github.com/gofiber/fiber/v2/internal/schema"
"github.com/gofiber/fiber/v2/utils"
Expand Down Expand Up @@ -62,6 +63,7 @@ type Ctx struct {
values [maxParams]string // Route parameter values
fasthttp *fasthttp.RequestCtx // Reference to *fasthttp.RequestCtx
matched bool // Non use route matched
viewBindMap *dictpool.Dict // Default view map to bind template engine
}

// Range data for c.Range
Expand Down Expand Up @@ -137,6 +139,9 @@ func (app *App) ReleaseCtx(c *Ctx) {
// Reset values
c.route = nil
c.fasthttp = nil
if c.viewBindMap != nil {
dictpool.ReleaseDict(c.viewBindMap)
}
app.pool.Put(c)
}

Expand Down Expand Up @@ -1060,6 +1065,20 @@ func (c *Ctx) Redirect(location string, status ...int) error {
return nil
}

// Add vars to default view var map binding to template engine.
// Variables are read by the Render method and may be overwritten.
func (c *Ctx) Bind(vars Map) error {
// init viewBindMap - lazy map
if c.viewBindMap == nil {
c.viewBindMap = dictpool.AcquireDict()
}
for k, v := range vars {
c.viewBindMap.Set(k, v)
}

return nil
}

// get URL location from route using parameters
func (c *Ctx) getLocationFromRoute(route Route, params Map) (string, error) {
buf := bytebufferpool.Get()
Expand Down Expand Up @@ -1113,25 +1132,8 @@ func (c *Ctx) Render(name string, bind interface{}, layouts ...string) error {
buf := bytebufferpool.Get()
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
}

}
// Pass-locals-to-views & bind
c.renderExtensions(bind)

rendered := false
for prefix, app := range c.app.appList {
Expand Down Expand Up @@ -1179,6 +1181,29 @@ func (c *Ctx) Render(name string, bind interface{}, layouts ...string) error {
return err
}

func (c *Ctx) renderExtensions(bind interface{}) {
ReneWerner87 marked this conversation as resolved.
Show resolved Hide resolved
if bindMap, ok := bind.(Map); ok {
// Bind view map
if c.viewBindMap != nil {
for _, v := range c.viewBindMap.D {
bindMap[v.Key] = v.Value
}
}

// Check if the PassLocalsToViews option is enabled (by default it is disabled)
if c.app.config.PassLocalsToViews {
// 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[utils.UnsafeString(key)]; !ok {
// Set the key and value in the bindMap
bindMap[utils.UnsafeString(key)] = val
}
})
}
}
}

// Route returns the matched Route struct.
func (c *Ctx) Route() *Route {
if c.route == nil {
Expand Down
118 changes: 114 additions & 4 deletions ctx_test.go
Expand Up @@ -2248,6 +2248,51 @@ func Test_Ctx_RenderWithLocals(t *testing.T) {
utils.AssertEqual(t, "<h1>Hello, World!</h1>", string(c.Response().Body()))

}

func Test_Ctx_RenderWithBind(t *testing.T) {
t.Parallel()

app := New()
c := app.AcquireCtx(&fasthttp.RequestCtx{})

c.Bind(Map{
"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_RenderWithBindLocals(t *testing.T) {
t.Parallel()

app := New(Config{
PassLocalsToViews: true,
})

c := app.AcquireCtx(&fasthttp.RequestCtx{})

c.Bind(Map{
"Title": "Hello, World!",
})

c.Locals("Summary", "Test")

defer app.ReleaseCtx(c)
err := c.Render("./.github/testdata/template2.html", Map{})

utils.AssertEqual(t, nil, err)
utils.AssertEqual(t, "<h1>Hello, World! Test</h1>", string(c.Response().Body()))

}

func Test_Ctx_RenderWithLocalsAndBinding(t *testing.T) {
t.Parallel()
app := New(Config{
Expand All @@ -2261,14 +2306,79 @@ func Test_Ctx_RenderWithLocalsAndBinding(t *testing.T) {
"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()))
}

func Benchmark_Ctx_RenderWithLocalsAndBinding(b *testing.B) {
var err error
app := New(Config{
PassLocalsToViews: true,
})
c := app.AcquireCtx(&fasthttp.RequestCtx{})

c.Bind(Map{
"Title": "Hello, World!",
})
c.Locals("Summary", "Test")

defer app.ReleaseCtx(c)

b.ReportAllocs()
b.ResetTimer()

for n := 0; n < b.N; n++ {
err = c.Render("./.github/testdata/template2.html", Map{})
}

utils.AssertEqual(b, nil, err)
utils.AssertEqual(b, "<h1>Hello, World! Test</h1>", string(c.Response().Body()))
}

func Benchmark_Ctx_RenderLocals(b *testing.B) {
var err error
app := New(Config{
PassLocalsToViews: true,
})
c := app.AcquireCtx(&fasthttp.RequestCtx{})

c.Locals("Title", "Hello, World!")

defer app.ReleaseCtx(c)

b.ReportAllocs()
b.ResetTimer()

for n := 0; n < b.N; n++ {
err = c.Render("./.github/testdata/template.html", Map{})
}

utils.AssertEqual(b, nil, err)
utils.AssertEqual(b, "<h1>Hello, World!</h1>", string(c.Response().Body()))
}

func Benchmark_Ctx_RenderBind(b *testing.B) {
var err error
app := New()
c := app.AcquireCtx(&fasthttp.RequestCtx{})

c.Bind(Map{
"Title": "Hello, World!",
})

defer app.ReleaseCtx(c)

b.ReportAllocs()
b.ResetTimer()

for n := 0; n < b.N; n++ {
err = c.Render("./.github/testdata/template.html", Map{})
}

utils.AssertEqual(b, nil, err)
utils.AssertEqual(b, "<h1>Hello, World!</h1>", string(c.Response().Body()))
}

// go test -run Test_Ctx_RestartRouting
func Test_Ctx_RestartRouting(t *testing.T) {
app := New()
Expand Down