iTemplate
The original (and still best) PHP template system
Template System Overview
In today's world, if you're not "MVC", you're nowhere. In short, that simply means that you need
to be programming with an eye on separating your layout from your logic. The iTemplate system facilitates
this for you, in an extremely logical methodology.
Here's the process...
- Design a template in full HTML
- Within that template, put in some HTML comments, called "PLUGINS" that identify to your program where you want certain things to show up (such as your menu, main output, etc).
- Write a program module that does your meat and potatoes work, and in the process generates some HTML (like a menu, search results, an form, etc)
- Read in the template you created earlier
- Replace those PLUGIN Comment tags with the HTML your program generated, where your template asks for it to show up.
Here's how a typical iTemplate enhanced program looks...
<?php
include_once("/path/to/iTemplate.inc.php");
include_once("/path/to/yourprogramlibrary.inc.php");
// Create a template object
$template = new PageTemplate (
array(
"template_directory" => "./data/",
"template_name" => "program.txt",
"default" => "default.txt",
"recursive" => ""
)
);
// Scan for plugins
$template->parse;
// Output to the browser
echo $template->execute;
exit;
?>
( SERIOUSLY, THAT'S IT )
Plugins
The heart and soul of the iTemplate system is the PLUGINS.
PLUGINS are simply a means of mating your program output to your template. We do this by using special
comment tags ("PLUGIN Tags") as triggers. When the iTemplate system sees a PLUGIN Tag in your template,
it replaces it with output from your program that matches.
This can happen in 2 ways:
- A matching function
- A global variable ($OUTPUT)
Here's a bit of code to illustrate ...
default.txt Page Template
<html>
<head>
<title><!-- PLUGIN:TITLE --></title>
</head>
<body>
<div style='background:silver;padding:8px'>
<!-- PLUGIN:MENU -->
</div>
<div style='padding:10px'>
<!-- PLUGIN:BODY -->
</div>
</body>
</html>
application.inc.php -- a php file that your
program includes, which does all of the thinking
<?php
function menu() {
return "cookie crumb menu ... "
}
function body() {
// Assume this function does a ton
// of work and creates some html at the
// end.
return "
<table>
... a whole mess of html
</table>
";
}
?>
What's happening here is this (reference the "Overview" Page, please). After your program creates
the tmeplate object, when it calls the "parse" method, it'll read in a file that looks like the
default.txt that we show in the below example.
The parse method finds 3 plguins: TITLE, MENU, BODY
It then looks for functions that match those plugin names in your source code. (These are not case sensitive,
by the way). In our example here, we have 2 obvious matches, one for MENU and one for BODY. These functions
RETURN their HTML instead of echo'ing it out.
Notice that the menu plugin set a global variable
$OUTPUT with some generated stuff. Since there's not
a "title" function in this program, the template system falls back to trying to find a key in the global variable
$OUTPUT instead.
When this program finishes running, all 3 of those comment tags will be replaced by HTML that the program
generated when asked for by the template.
Note that plugins, both internal and custom
can also accept pamameters ... this feature is not discussed here, but only in the actual program documentation.
As a programmer, all you have to do is this ...
Create templates with plugin tags that match up to functions of the same name. Those functions will
then output their HTML to your template automagically where the plugin tags are.
Custom Plugins
Similar to regular plugins, custom plugins (or "User Defined" plugins) are plugins that generate HTML
OUTSIDE of your normal application code. These allow 3rd party developers (anyone, really) to develop
a plugin that's perhaps totally unrelated to your application to be included in the template.
Essentially, the allowance of these custom plugins gives your program an immediate "3rd Party PLUGIN API"
that you can market as a feature, if that sort of thing is important for your project.
A good example of this, might be some ad code that depends on some environmental stuff to output itself correctly, e.g:
In your template:
<!-- PLUGIN:CUSTOM:ads -->
./data/custom/ads.inc
<?php
function ads() {
global $user;
$adcode = '';
if ( $user->paid_to_hide_ads == "YES" ) {
$adcode = '';
}
else {
$adcode = "
....
";
}
return $adcode;
}
?>
Notice that everything matches ...
· the custom plugin is called "ads"
· the custom plugin file is called "ads.inc"
· the function in the plugin file is called "ads"
Sub Templates
The Sub-Template system allows you to further refine your program's output, giving more control to the
designers, and allowing the program that you write to simply deal with the data.
Let's take a look at the simple example of a blog. If you imagine a blog article screen, it's going to
have 2 main elements to it:
· The Article Itself
· Any Replies/Comments made by other users
Here's the principle plugin function:
Version 1: Embedded HTML (the old way)
function body() {
global $article;
global $replies;
$output = '';
// Let's assume here that we already have retrieved
// the article as an associative array and all of
// the replies as an array of associative arrays.
$output = "
<h2>$article[title]</h2>
<div style='padding:4px; background:black; color:white'>
$article[author] / $article[post_date]
</div>
<div style='padding:10px;'>$article[text]</div>
";
foreach ( $replies as $reply ) {
$output .= "
<div style='margin:left:25px; padding-bottom:10px;'>
$reply[reply_text]
<p align='right'>$reply[author]</p>
</div>
";
}
return $output;
}
Version 2: Using an iTemplate Subtemplate and doing this the MVC way ...
The code is a little bit longer, but it completely separates the HTML from
the logic, making the code infinitely more readable, and allows you to make
layout and style changes in sub-template files, and not have to monkey
with your source code when the designers change their mind ;)
Elsewhere in your code, or an external file ...
$article_template:
<h2>[title]</h2>
<div style='padding:4px; background:black; color:white'>
[author] / [post_date]
</div>
<div style='padding:10px;'>$article[text]</div>
$replies_template:
<div style='margin:left:25px; padding-bottom:10px;'>
[reply_text]
<p align='right'>[author]</p>
</div>
function body() {
global $article;
global $replies;
global $article_template;
global $replies_template;
$output = '';
// Create 2 new template objects, one for the articles
// and one for replies
$a_template = new SubTemplate (
array(
"front" => '[',
"back" => ']',
"template_text" => $article_template
)
);
$r_template = new SubTemplate (
array(
"front" => '[',
"back" => ']',
"template_text" => $replies_template
)
);
// First the articles. Assign the [values] in the template
// with the matching values from the associative array
$a_template>set_values( $article );
$output .= $a_template>merge();
// Now, loop through the replies, doing the same thing
foreach ( $replies as $reply ) {
$r_template>set_values( $reply );
$output .= $r_template>merge();
}
return $output;
}