I’ve starting playing with template engines as a way to separate my presentation from logic.
I’ve looked around some existing applications and many of them have their head code in every page template, which to me could be problematic if you need to change the head across the site. It makes more sense to me having a function run outside the page view script that applies the head code afterwards, but then again you’re assuming every page will be the same. Its the chicken and the egg!
With this in mind, what approaches do any of you go with - head in each template, reusable function or different method all together.
When I talk about head code, it also refers to things like site logos and menus not just the HTML head - in other words things that could be considered the header for a page. I may be looking at this differently as well, so please give me an insight into what you do in terms of breaking up reusable site-wide layouts when using template engines.
Have layouts (overall templates into which other templates fit). The layouts contain the head portion, only the body gets replaced by the template of the individual action. Even then, the head can be partially dynamic. For example, you might put placeholders or function calls for the title, meta tags, scripts and stylesheets. These get replaced/filled with the values dependent upon the individual page being displayed.
I have taken to the idea of reusable modules that can be executed within any template or module at any time. So I would separate out the header and footer for a site into two separate modules then execute them within the master module.
Those two lines within my master template would execute the footer and header independently and return the HTML contents. The advantages of such a system is that you can reuse the header and footer anywhere at any time without replicating code because I’m not a fan of replication and doing things more than once.
The header and footer are essentially completely decoupled from any other template or module meaning they can be requested on their own or within something else.
definitely put the header and footer into an include and call that from your controller.
As pointed out by Dan, you can customize aspects of the header on a page by page basis, but you can also display a completely different header or footer based on the requirements of the page.
Every page generation I put in a custom title, sometimes a custom meta description / keywords, and have placeholders for special case css and javascript. That way you only call the elements you need on any given page.
I have a master template in my system, which all other templates fit into. The master template includes the header, footer, and a marker to show where the body should be inserted, which is then handled with the other templates in the system. It also allows for included templates (like include files) if that route makes more sense.
That really looks no better than <? include ‘header.php’; ?> to me… what if the module does something different based on its output… e.g. for my admin login control I don’t want to expose admin related javascript unless you’re logged in.
It’s far better to use a “push” method than a “pull” method as it gives you total control.
My modules look like this:
<?php
class MyModule extends Module {
public function main() {
$this->usesJavascript('js/foo.js');
$this->usesCss('css/foo.css');
$this->title = 'module';
$this->write('left block', 'left');
$this->write('right block', 'right');
}
}
?>
Which get written into a template which looks like this:
<html>
<head>
<title>{title}</title>
{head} <!-- pull in js/css html from the module -->
</head>
<body>
<div class="left">{module output="left"}</div>
<div class="right">{module output="right"}</div>
</body>
</html>
By passing the module to the template, rather than calling the module from the template you get far higher flexibility. This also reduces the repetition because you dont need to call in the header for each specific module, the one you’re working with is passed to the general layout and it’s done.
All modules have access to the master program. Any module at any time can request that type of information from the master program and change its behavior accordingly.
That can also be done. Any module can be executed from within a template or within another module and embedded into the template.
That logic would reside inside the module, not the template. In your case it seems like the best solution would be to make the Admin and Front-End Headers separate modules as well which the Header module would delegate.
This is I would achieve that switch.
Site.Demo1.Module.Header
class Demo1_Header extends Module {
public function execute($arrArgs) {
if($this->_objMCP->getUsersId()) {
$this->_arrTemplateData['HEADER_TPL'] = $this->_objMCP->executeModule('Site.*.Module.Header.AdminHeader');
} else {
$this->_arrTemplateData['HEADER_TPL'] = $this->_objMCP->executeModule('Site.*.Module.Header.FrontEndHeader');
}
return 'Header/Header.php';
}
}
Thanks for the feedback so far, it has been extremely helpful.
I like the idea of working with a master template and I’m looking at something like that, with the possibility of loading one of a set of available templates based on parameter set in module (i.e. admin, front end, etc). I take it this master template would be loaded after the body has been built by the calling method?
I’ve read several times about the concepts of “pushing” or “pulling” actions between modules; wouldn’t mind understanding them a bit more. As far as I understand it, pulling actions are instances when you extract data from another location; pushing actions on the other hand pass on their responsibilities somewhere else (i.e. function ProcessForm($this) …).
Could someone explain this to me in layman’s terms, or point me in the right direction? I appreciate “push” is a more desirable method, but just can’t visualise how its done.
My master template works by basically swapping the template you are trying to use with the master one, then 'include’ing the intended template in the appropriate place. I have MasterView class which sorts out all the variables and templating in the master template, and all the other View helper classes extend the master view.
$template = new Template('wrapper_01.tpl');
$template->content = new Template('login.tpl', $defaults);
echo $template;
edit profile page
$template = new Template('wrapper_02.tpl', $defaults);
$template->menu = new Template('profile_menu.tpl', $defaults);
$template->content = new Template('profile_edit.tpl', $defaults);
echo $template;
Note:$defaults is an array that gets extracted to the template, that is the way you pass variables to it.
If you do it like that, you can give the HTML to a designer, and they can work with it in dreamweaver/front page…/whatever they use without having to worry that they mess something up.
That tells me you will have problems with outside, inside, popup pages.
And that you have some logic in there, to see if the user is logged in or not, to be able to include the appropriate header/footer file.
It also says your header/footer is split in two pages (2 includes).
That works, I used to do it like that for the longest time, except that when you deal with integrators / designers, they won’t put the two files together easily (the work-flow gets complicated, especially with designers that don’t know **** about development but think they do).
That says that you have multiple classes to deal with your templates. Each class potentially containing business logic (or some kind of IFs).
That means, if you make a different site, that is not the same as your current one, you cannot just reuse the code. You will have to modify those classes / html templates.
[INDENT]Than again, even in my suggested solution you end up with IFs in the HTML. Ifs for the permissions / ACL…
Ex: show the EDIT link/button on a page only if the logged in user is an administrator or page owner.
Suggestions on how to take this off are welcomed.[/INDENT]
In reality, you only need 1 template class (the one that has the template code in it), and possibly one or two helper classes that will set the defaults on those templates (basically some factory class for templates to save you typing / duplicate code).
Well firstly you are wrong about the header and footer being separate - that’s what the master template is for - and you are wrong about business logic being inside my view helpers. The job of the view helpers is to take the data from models and perhaps some other sources (xml files for example) and insert them into the template. There is no business logic there - I leave that for the models and controllers.
The MasterView and BaseView view helpers are perfectly reusable if needed - the BaseView class contains functions and methods to help escape output, perform common tasks, loading and dealing with templates etc, whereas the MasterView is changed to fit the site and contains things that appear in the master template (such as loading stylesheets, scripts etc), but not the individual pages, which are handled by their own view helper classes.
An example of a master template on one of my sites is below:
They aren’t yet part of that site, but they will just be different sections of the main template. Popup boxes can be created on the fly with JavaScript.
That’s when you will have the problems I described.
If the user is logged in, you will need a different HTML for that wrapper (most the time, you will want to keep the header only).
Since your always including that one template, you will need an IF somewhere to show inner or outer wrapper.
Same for the popup. You will need another wrapper for it, so you will either have your header includes duplicated, or end up with a bunch of IFs in your template (or not use a template for it…).
Yup, and there’s no other way around it. If you want to show different content for logged in users, you HAVE to either have 1 template with 2 separate sections, or 2 separate templates. Maintenance is no harder on one than the other, and neither is a real problem.
Look at my example again, since you don’t have that problem there.
Your business logic would be in the controller, instead of the view (template).
# This is in the parent controller, so you only have this once in your site
if (isPopup()) {
$template = new Template('popup_wrapper.tpl');
} else if (isLoggedIn()) {
$template = new Template('inside_wrapper.tpl');
$template->menu = new Template('profile_menu.tpl', $defaults);
} else {
$template = new Template('outside_wrapper.tpl');
}
# This is in your page controller, using the [I]$template[/I] from the parent controller.
$template->content = new Template('terms_of_service.tpl', $defaults);
echo $template;
You can also just copy paste the HTML from the wrappers to your project, change the css for the new design, and your done.
If you want one wrapper changed, you just change that one, no need to know about the other 20 possibilities.
But if you update something common to them both, you have to make the same change twice - violating DRY. Also, I’d argue that isn’t business logic - it’s ‘view’ logic in a way. Deciding which section of a template to use based on some a flag belongs in the view, not the controller, I’d say.
Also, a nested if() statement is pretty bad - it’s basically saying your template has 3 ‘states’ - popup, logged in or other. What if they are logged in and you want a popup for example? Adding new possibilities is a lot harder too.
If you have something common in the two templates, you will have an include block in both of them.
If your logged in, and want a popup, well, that IF is first, so you get the popup template.
If the user HAS to be logged in to see the page, then the controller takes care of that.