include("class.FastTemplate.php3"); $tpl = FastTemplate("/path/to/templates"); $tpl->define( array( main => "main.tpl", row => "table_row.tpl", all => "table_all.tpl" ));
$tpl->assign(TITLE, "I am the title."); $defaults = ( array( FONT => '<font size=+2 face=helvetica>', EMAIL => 'cdi@thewebmasters.net' ));
$tpl->assign($defaults); $tpl->parse(ROWS, ".row"); // the '.' appends to ROWS $tpl->parse(CONTENT, array("row", "all")); $tpl->parse(CONTENT, "main"); $tpl->FastPrint(CONTENT);
$raw = $tpl->fetch("CONTENT"); echo "$raw\n";
But see below for more complex examples.
A template is a text file with variables in it. When a template is parsed, the variables are interpolated to text. (The text can be a few bytes or a few hundred kilobytes.) Here is a simple template with one variable ('{NAME}'):
Hello {NAME}. How are you?
When are templates useful?
Templates are very useful for CGI programming, because adding HTML to your PHP code clutters your code and forces you to do any HTML modifications. By putting all of your HTML in seperate template files, you can let a graphic or interface designer change the look of your application without having to bug you, or let them muck around in your PHP code.
Why use FastTemplate?
Speed
FastTemplate parses with a single regular expression. It just does simple variable interpolation (i.e. there is no logic that you can add to templates - you keep the logic in the code). That's why it's has 'Fast' in it's name!
Flexibility
The API is robust and flexible, and allows you to build very complex HTML documents/interfaces. It is also completely written in PHP and (should) work on Unix or NT. Also, it isn't restricted to building HTML documents -- it could be used to build any ascii based document (postscript, XML, email - anything).
What are the steps to use FastTemplate?
The main steps are:
1. define 1a.cache 2. assign 3. parse 3a.cache write 4. FastPrint
These are outlined in detail in CORE METHODS below.
define()
maps a template filename to a (usually
shorter) name;
$tpl = new FastTemplate("/path/to/templates");
$tpl->define( array( main => "main.tpl", footer => "footer.tpl" ));
This new name is the name that you will use to refer to the templates.
Filenames should not appear in any place other than a
define().
(Note: This is a required step! This may seem like an annoying extra step when you are dealing with a trivial example like the one above, but when you are dealing with dozens of templates, it is very handy to refer to templates with names that are indepandant of filenames.)
TIP: Since define()
does not actually load the templates, it
is faster and more legible to define all the templates with one call to
define().
And probably never will be. The purpose of this class is to eliminate HTML from your PHP code, not to create new ways of adding it back in.
You can define dynamic content within a static template. (Lists) Here's an
example of define_dynamic();
$tpl = new FastTemplate("./templates");
$tpl->define( array( main => "main.tpl", table => "dynamic.tpl" ));
$tpl->define_dynamic( "row" , "table" );
This tells FastTemplate that buried in the ``table'' template is a dynamic block, named ``row''. In older verions of FastTemplate (pre 0.7) this ``row'' template would have been defined as it's own file. Here's how a dynamic block appears within a template file;
<!-- NAME: dynamic.tpl --> <table>
<!-- BEGIN DYNAMIC BLOCK: row --> <tr> <td>{NUMBER}</td> <td>{BIG_NUMBER}</td> </tr> <!-- END DYNAMIC BLOCK: row -->
</table> <!-- END: dynamic.tpl -->
The syntax of your BEGIN and END lines needs to be VERY exact. It is case sensitive. The code block begins on a new line all by itself. There cannot be ANY OTHER TEXT on the line with the BEGIN or END statement. (although you can have any amount of whitespace before or after) It must be in the format shown;
<!-- BEGIN DYNAMIC BLOCK: handle_name -->
The line must be exact, right down to the spacing of the characters. The
same is true for your END line. The BEGIN and END lines cannot span
multiple lines. Now when you call the parse()
method,
FastTemplate will automatically spot the dynamic block, strip it out, and
use it exactly as if you had defined it as a stand-alone template. No
additional work is required on your part to make it work - just define it,
and FastTemplate will do the rest. Included with this archive should have
been a file named
define_dynamic.phtml which shows a working example of a dynamic block.
There are a few rules when using dynamic blocks - dynamic blocks should not
be nested inside other dynamic blocks - strange things WILL occur. You
-can- have more than one nested block of code in a page, but of course, no
two blocks can share the same defined handle. The error checking for
define_dynamic()
is miniscule at best. If you define a dynamic
block and FastTemplate fails to find it, no errors will be generated, just
really weird output. (FastTemplate will not append the dynamic data to the
retured output) Since the BEGIN and END lines are stripped out of the
parsed results, if you ever see your BEGIN or END line in the parsed
output, that means that FastTemplate failed to find that dynamic block.
$tpl->clear_dynamic("row");
Would completely strip all of the unparsed dynamic blocks named ``row'' from the parent template. This method won't do a thing if the template has already been parsed! (Because the required BEGIN and END lines have been removed through the parsing) This method works well when you are accessing a database, and your ``rows'' may or may not return anything to print to the template. If your database query doesn't return anything, you can now strip out the rows you've set up for the results. (Gee, maybe I ran into this problem myself ? :-)
assign()
assigns values for variables. In order for
a variable in a template to be interpolated it must be assigned. There are
two forms which have some important differences. The simple form, is to
accept an array and copy all the key/value pairs into an array in
FastTemplate. There is only one array in FastTemplate, so assigning a value
for the same key will overwrite that key.
$tpl->assign(TITLE => "king kong"); $tpl->assign(TITLE => "godzilla"); // overwrites "king kong"
$tpl->parse(MAIN, "main"); // regular $tpl->parse(MAIN, array ( "table", "main") ); // compound $tpl->parse(MAIN, ".row"); // append
In the regular version, the template named ``main'' is loaded if it hasn't been already, all the variables are interpolated, and the result is then stored in FastTemplate as the value MAIN. If the variable '{MAIN}' shows up in a later template, it will be interpolated to be the value of the parsed ``main'' template. This allows you to easily nest templates, which brings us to the compound style.
The compound style is designed to make it easier to nest templates. The following are equivalent:
$tpl->parse(MAIN, "table"); $tpl->parse(MAIN, ".main");
// is the same as:
$tpl->parse(MAIN, array("table", "main")); // this form saves function calls and makes your code cleaner
It is important to note that when you are using the compound form, each template after the first, must contain the variable that you are parsing the results into. In the above example, 'main' must contain the variable '{MAIN}', as that is where the parsed results of 'table' is stored. If 'main' does not contain the variable '{MAIN}' then the parsed results of 'table' will be lost.
The append style allows you to append the parsed results to the target variable. Placing a leading dot . before a defined file handle tells FastTemplate to append the parsed results of this template to the returned results. This is most useful when building tables that have an dynamic number of rows - such as data from a database query.
strict()
is on (it is on by default) all variables found
during template parsing that are unresolved have a warning printed to
STDERR;
[FastTemplate] Warning: no value found for variable: SOME_VAR
Also, the variables will be left in the output document. This was done for
two reasons: to allow for parsing to be done in stages (i.e. multiple
passes), and to make it easier to identify undefined variables since they
appear in the parsed output. If you want to replace unknown variables with
an empty string, see: no_strict().
Note: STDERR output should be captured and logged by the webserver. With apache (and unix!) you can tail the error log during development to see the results as in;
tail -f /var/log/httpd/error_log
no_strict()
is required to replace unknown variables with an
empty string. By default, all instances of FastTemplate behave as is
strict()
was called. Also, no_strict()
must be
set for each instance of FastTemplate;
$tpl = new FastTemplate("/path/to/templates"); $tpl->no_strict();
cache_expire
method sets the time of life for a cached
region. The age is specified in seconds. For example, if the cache was written to
at 11:51:42, and the expire is set to 20 seconds, the cache will be invalidated at
11:52:02.
This value if only useful during cache reads, not cache writes. This means that you can not set global cache policy for a region, but does allow you to easily change times when the cache will expire.
If neither cache_expire
nor cache_refresh
are called,
FastTemplate will use a cache_expire
of 600 seconds.
It is possible to call both cache_expire
and cache_refresh
for the same read. In this case, if either condition is true, the cache will
be invalidated.
$tpl = new FastTemplate("/path/to/templates"); $tpl->define(array(main=>"template.tpl")); $tpl->cache_expire(main, 20); // This will invalidate the cache after 20 seconds.
cache_refresh
method sets the frequency by which a
cached region is invalidated. The frequency can be one of minute
,
quarterHour
, halfHour
, hour
,
halfDay
, day
, or month
. For example, if
you are refreshing every minute, and the cache is written at 11:51:42, the
cache will be invalidated at 11:52:00.
This value if only useful during cache reads, not cache writes. This means that you can not set global cache policy for a region, but does allow you to easily change times when the cache will expire.
If neither cache_expire
nor cache_refresh
are called,
FastTemplate will use a cache_expire
of 600 seconds.
It is possible to call both cache_expire
and cache_refresh
for the same read. In this case, if either condition is true, the cache will
be invalidated.
$tpl = new FastTemplate("/path/to/templates"); $tpl->define(array(main=>"template.tpl")); $tpl->cache_refresh(main, "hour"); // This will invalidate the cache on the hour..
TRUE
if the region has a valid
cache. (See cache_expire
and cache_refresh
for
information about cache invalidation.) If a valid cache file is not
available, this method will return FALSE.
As a side effect, when this function returns TRUE
, it acts as
if parse
had been called. In other words, this function will
load the cached file into memory and insert it into RETURN
.
$tpl = new FastTemplate("/path/to/templates"); $tpl->define(array(main=>"template.tpl")); $tpl->cache_refresh(main, "hour"); // This will invalidate the cache on the hour. if (!$tpl->is_cached (MAIN, main)) { $body["title"] = "Cache test"; $tpl->assign($body); $tpl->parse(MAIN, main); $tpl->write_cache (MAIN, "main"); } $tpl->FastPrint();
$tpl = new FastTemplate("/path/to/templates"); $tpl->define(array(main=>"template.tpl")); $tpl->cache_refresh(main, "hour"); // This will invalidate the cache on the hour. if (!$tpl->is_cached (MAIN, main)) { $body["title"] = "Cache test"; $tpl->assign($body); $tpl->parse(MAIN, main); $tpl->write_cache (MAIN, "main"); } $tpl->FastPrint();
FastPrint()
prints the contents of the named
variable. If no variable is given, then it prints the last variable that
was used in a call to parse()
which I find is a reasonable
default.
$tpl->FastPrint(); // continuing from the last example, would // print the value of MAIN
$tpl->FastPrint("MAIN"); // ditto
This method is provided for convenience. If you need to print somewhere
else (a socket, file handle) you would want to fetch()
a
reference to the data first:
$data = $tpl->fetch("MAIN"); fwrite($fd, $data); // save to a file
$tpl->parse(CONTENT, "main"); $content = $tpl->fetch("CONTENT"); print $content; // print to STDOUT fwrite($fd, $content); // write to filehandle
assign().
This allows you to easily pass variables around
within functions by using the FastTemplate class to handle
``globalization'' of the variables. For example;
$tpl->assign( array( TITLE => $title, BGCOLOR => $bgColor, TEXT => $textColor ));
(sometime later...) $bgColor = $tpl->get_assigned(BGCOLOR);
clear()
functions are for use anywhere where
your scripts are persistant. They generally aren't needed if you are
writing CGI scripts.
clear()
Clears the internal references that store data passed
to parse().
clear()
accepts individual
references, or array references as arguments.
Often clear()
is at the end of a script:
$tpl->FastPrint("MAIN"); $tpl->clear("MAIN");
or
$tpl->FastPrint("MAIN"); $tpl->FastPrint("CONTENT"); $tpl->clear(array("MAIN","CONTENT"));
If called with no arguments, removes ALL references that have been set via
parse().
clear()
$tpl->assign(KEY = val);
If called with no arguments, it removes all references from the array.
(Same as clear_assign()
)
$tpl->assign( array( MOVIE => "The Avengers", RATE => "Sucked" ));
$tpl->clear_href("MOVIE"); // Now only {RATE} exists in the assign() array
$tpl->define();
Note: The hash that holds the loaded templates is not touched with this
method. ( See: clear_tpl()
) Accepts a single file handle, an
array of file handles, or nothing as arguments. If no argument is given, it
clears ALL file handles.
$tpl->define( array( MAIN => "main.tpl", BODY => "body.tpl", FOOT => "foot.tpl" ));
// some code here
$tpl->clear_define("MAIN");
$tpl->define(MAIN,"main.tpl" ); // assign(), parse() etc etc...
$tpl->clear_tpl(MAIN); // Loaded template now unloaded.
$tpl->clear_define(); $tpl->clear_href(); $tpl->clear_tpl(); $tpl->clear_parse();
In fact, that's exactly what it does.
{([A-Z0-9_]+)}
This means, that a variable must begin with a curly brace '{'. The second and remaining characters must be uppercase letters or digits 'A-Z0-9'. Remaining characters can include an underscore. The variable is terminated by a closing curly brace '}'.
For example, the following are valid variables:
{FOO} {F123F} {TOP_OF_PAGE}
strict()
and no_strict()
for more
info.
Some examples will make this clearer.
Assume:
$FOO = "foo"; $BAR = "bar"; $ONE = "1"; $TWO = "2"; $UND = "_"; Variable Interpolated/Parsed ------------------------------------------------ {FOO} foo {FOO}-{BAR} foo-bar {ONE_TWO} {ONE_TWO} // {ONE_TWO} is undefined! {ONE}{UND}{TWO} 1_2 ${FOO} $foo $25,000 $25,000 {foo} {foo} // Ignored, it's not valid, nor will it // generate any error messages.
Below are the templates. (Pretend each one is in a separate file.)
<!-- NAME: main.tpl --> <html> <head><title>{TITLE}</title> </head> <body> {MAIN} </body> </html> <!-- END: main.tpl --> <!-- NAME: table.tpl --> <table> {ROWS} </table> <!-- END: table.tpl --> <!-- NAME: row.tpl --> <tr> <td>{NUMBER}</td> <td>{BIG_NUMBER}</td> </tr> <!-- END: row.tpl -->
Now we can start coding...
/* START */
<? include("class.FastTemplate.php3"); $tpl = new FastTemplate("/path/to/templates"); $tpl->define( array( main => "main.tpl", table => "table.tpl", row => "row.tpl" ));
$tpl->cache_expire (main, 3600); $tpl->cache_refresh (main, "day");
$tpl->assign(TITLE,"FastTemplate Test");
if (!$tpl->is_cached (ROWS,".row")) { for ($n=1; $n <= 3; $n++) { $Number = $n; $BigNum = $n*10; $tpl->assign( array( NUMBER => $Number, BIG_NUMBER => $BigNum ));
$tpl->parse(ROWS,".row"); } $tpl->write_cache (ROWS,".row"); } $tpl->parse(MAIN, array("table","main")); Header("Content-type: text/plain"); $tpl->FastPrint(); exit; ?>
When run it returns:
<!-- NAME: main.tpl --> <html> <head><title>FastTemplate Test</title> </head> <body> <!-- NAME: table.tpl --> <table> <!-- NAME: row.tpl --> <tr> <td>1</td> <td>10</td> </tr> <!-- END: row.tpl --> <!-- NAME: row.tpl --> <tr> <td>2</td> <td>20</td> </tr> <!-- END: row.tpl --> <!-- NAME: row.tpl --> <tr> <td>3</td> <td>30</td> </tr> <!-- END: row.tpl --> </table> <!-- END: table.tpl -->
</body> </html> <!-- END: main.tpl -->
If you're thinking you could have done the same thing in a few lines of plain PHP, well yes you probably could. But, how would a graphic designer tweak the resulting HTML? How would you have a designer editing the HTML while you're editing another part of the code? How would you save the output to a file, or pipe it to another application? How would you make your application multi-lingual? How would you build an application that has options for high graphics, or text-only? FastTemplate really starts to shine when you are building mid to large scale web applications, simply because it begins to seperate the application's generic logic from the specific implementation.
Caching functions originally by: "JP"
PHP3 port by CDI cdi@thewebmasters.net
This program is free software; you can redistribute it and/or modify it
under the GNU Library General Public License, with the following stipulations;
Changes or modifications must retain these Copyright statements. Changes or
modifications must be submitted to all AUTHORS.
This program is released under the Library General Public License.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the Artistic License for more
details. This software is distributed AS-IS.
Address Bug Reports or Comments on THIS PHP VERSION ONLY to
The latest version of this class should be available from the following
locations:
http://zoned.net/~xkahn/php/fasttemplate/
This is a modified version of the CGI::FastTemplate man page, originally
written by Jason Moore jmoore@sober.com. Forgive me if I
didn't get all the Perlisms out of the example code.
This is not a complete port, the
The variable declaration method has changed from the Perl version's
$(A-Z0-9_)+ to {(A-Z0-9_)+}, which means you'll have to edit all your
templates. The beginning and close curly braces allow for much faster and
more accurate templates.
http://www.phpbuilder.com/columns/jprins20000201.php3
with code by: Spencer D. Mindlin
http://www.phpbuilder.com/columns/spencer20000208.php3
PHP3 Version Copyright (c) 1999 CDI, cdi@thewebmasters.net, All Rights Reserved.
Perl Version Copyright (c) 1998 Jason Moore jmoore@sober.com. All Rights Reserved.
Original Perl module CGI::FastTemplate by Jason Moore jmoore@sober.com
CDI, cdi@thewebmasters.net, or to
CyberSites, Inc. (all caching related questions) xkahn@cybersites.com
DOCUMENTATION
Sascha Schumann has written a very nice FastTemplate tutorial. It's on the
PHPBuilder.com web site at;
define_nofile(array()),
and/or define_raw(array())
methods were not implemented in
this port since I had no need or use for them. Some of the methods are
implemented differently (mostly due to PHP's stronger variable type
requirements.) The functionality of each method has remained the same. The
define_dynamic()
method is completely new to this PHP port and
does not appear in the Perl version.
SEE ALSO
CGI::FastTemplate Perl module, available from CPAN - http://www.cpan.org