Provide combined parse and execute method for the template renderer.

This commit is contained in:
mikestefanello 2021-12-21 11:00:32 -05:00
parent 92bb2d9d7b
commit 0e2625bf51
5 changed files with 46 additions and 46 deletions

View file

@ -47,16 +47,26 @@ func (c *Controller) RenderPage(ctx echo.Context, page Page) error {
page.AppName = c.Container.Config.App.Name
}
// Parse the templates in the page and store them in a cache, if not yet done
if err := c.parsePageTemplates(page); err != nil {
ctx.Logger().Errorf("failed to parse templates: %v", err)
return echo.NewHTTPError(http.StatusInternalServerError, "Internal server error")
}
// Parse and execute the templates for the Page
// As mentioned in the documentation for the Page struct, the templates used for the page will be:
// 1. The layout/base template specified in Page.Layout
// 2. The content template specified in Page.Name
// 3. All templates within the components directory
// Also included is the function map provided by the funcmap package
buf, err := c.Container.TemplateRenderer.ParseAndExecute(
"controller",
page.Name,
page.Layout,
[]string{
fmt.Sprintf("layouts/%s", page.Layout),
fmt.Sprintf("pages/%s", page.Name),
},
[]string{"components"},
page,
)
// Execute the parsed templates to render the page
buf, err := c.executeTemplates(page)
if err != nil {
ctx.Logger().Errorf("failed to execute templates: %v", err)
ctx.Logger().Errorf("failed to parse and execute templates: %v", err)
return echo.NewHTTPError(http.StatusInternalServerError, "Internal server error")
}
@ -105,31 +115,6 @@ func (c *Controller) cachePage(ctx echo.Context, page Page, html *bytes.Buffer)
ctx.Logger().Infof("cached page")
}
// parsePageTemplates parses the templates for the given Page and caches them to avoid duplicate operations
// If the configuration indicates that the environment is local, the cache is bypassed for template changes
// can be seen without having to restart the application.
// As mentioned in the documentation for the Page struct, the templates used for the page will be:
// 1. The layout/based template specified in Page.Layout
// 2. The content template specified in Page.Name
// 3. All templates within the components directory
// Also included is the function map provided by the funcmap package
func (c *Controller) parsePageTemplates(page Page) error {
return c.Container.Templates.Parse(
"controller",
page.Name,
page.Layout,
[]string{
fmt.Sprintf("layouts/%s", page.Layout),
fmt.Sprintf("pages/%s", page.Name),
},
[]string{"components"})
}
// executeTemplates executes the cached templates belonging to Page and renders the Page within them
func (c *Controller) executeTemplates(page Page) (*bytes.Buffer, error) {
return c.Container.Templates.Execute("controller", page.Name, page.Layout, page)
}
// Redirect redirects to a given route name with optional route parameters
func (c *Controller) Redirect(ctx echo.Context, route string, routeParams ...interface{}) error {
return ctx.Redirect(http.StatusFound, ctx.Echo().Reverse(route, routeParams))

View file

@ -127,7 +127,7 @@ func TestController_RenderPage(t *testing.T) {
}
// Check the template cache
parsed, err := c.Templates.Load("controller", p.Name)
parsed, err := c.TemplateRenderer.Load("controller", p.Name)
assert.NoError(t, err)
// Check that all expected templates were parsed.
@ -135,7 +135,7 @@ func TestController_RenderPage(t *testing.T) {
expectedTemplates := make(map[string]bool)
expectedTemplates[p.Name+config.TemplateExt] = true
expectedTemplates[p.Layout+config.TemplateExt] = true
components, err := ioutil.ReadDir(c.Templates.GetTemplatesPath() + "/components")
components, err := ioutil.ReadDir(c.TemplateRenderer.GetTemplatesPath() + "/components")
require.NoError(t, err)
for _, f := range components {
expectedTemplates[f.Name()] = true

View file

@ -19,15 +19,15 @@ import (
)
type Container struct {
Web *echo.Echo
Config *config.Config
Cache *cache.Cache
cacheClient *redis.Client
Database *sql.DB
ORM *ent.Client
Mail *MailClient
Auth *AuthClient
Templates *TemplateRenderer
Web *echo.Echo
Config *config.Config
Cache *cache.Cache
cacheClient *redis.Client
Database *sql.DB
ORM *ent.Client
Mail *MailClient
Auth *AuthClient
TemplateRenderer *TemplateRenderer
}
func NewContainer() *Container {
@ -140,12 +140,12 @@ func (c *Container) initAuth() {
}
func (c *Container) initTemplateRenderer() {
c.Templates = NewTemplateRenderer(c.Config)
c.TemplateRenderer = NewTemplateRenderer(c.Config)
}
func (c *Container) initMail() {
var err error
c.Mail, err = NewMailClient(c.Config, c.Templates)
c.Mail, err = NewMailClient(c.Config, c.TemplateRenderer)
if err != nil {
panic(fmt.Sprintf("failed to create mail client: %v", err))
}

View file

@ -14,4 +14,5 @@ func TestNewContainer(t *testing.T) {
assert.NotNil(t, c.ORM)
assert.NotNil(t, c.Mail)
assert.NotNil(t, c.Auth)
assert.NotNil(t, c.TemplateRenderer)
}

View file

@ -44,6 +44,20 @@ func NewTemplateRenderer(cfg *config.Config) *TemplateRenderer {
return t
}
func (t *TemplateRenderer) ParseAndExecute(module, key, name string, files []string, directories []string, data interface{}) (*bytes.Buffer, error) {
var buf *bytes.Buffer
var err error
if err = t.Parse(module, key, name, files, directories); err != nil {
return nil, err
}
if buf, err = t.Execute(module, key, name, data); err != nil {
return nil, err
}
return buf, nil
}
func (t *TemplateRenderer) Parse(module, key, name string, files []string, directories []string) error {
cacheKey := t.getCacheKey(module, key)