diff --git a/controller/controller.go b/controller/controller.go index ff84f69..7215c77 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -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)) diff --git a/controller/controller_test.go b/controller/controller_test.go index 236cfca..7ca095d 100644 --- a/controller/controller_test.go +++ b/controller/controller_test.go @@ -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 diff --git a/services/container.go b/services/container.go index b0117f3..4a3853b 100644 --- a/services/container.go +++ b/services/container.go @@ -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)) } diff --git a/services/container_test.go b/services/container_test.go index fd40048..8cbe18e 100644 --- a/services/container_test.go +++ b/services/container_test.go @@ -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) } diff --git a/services/templates.go b/services/template_renderer.go similarity index 88% rename from services/templates.go rename to services/template_renderer.go index 28f34e5..7d0c118 100644 --- a/services/templates.go +++ b/services/template_renderer.go @@ -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)