Académique Documents
Professionnel Documents
Culture Documents
PHPTAL Manual
PHP Template Attribute Language
Laurent Bédubourg
Kornel Lesi!ski
Dan Sheppard
Anton Valeriyevich Andriyevskyy
Revision History
Table of Contents
1. Introduction
2. Why use PHPTAL
3. Installation
4. First example
5. Template Attribute Language
1. Attribute priority
2. TAL namespace
1. tal:define
2. tal:condition
3. tal:repeat
4. tal:omit-tag
5. tal:replace
6. tal:content
7. tal:attributes
1. Optional attributes
8. tal:on-error
3. METAL namespace
1. metal:define-macro
2. metal:use-macro
3. metal:define-slot
4. metal:fill-slot
4. I18N namespace
1. i18n:translate
2. i18n:attributes
3. i18n:name
4. XHTML in translations
5. PHPTAL namespace
1. phptal:debug
2. phptal:cache
1. Instant refreshing
2. Limitations:
3. phptal:tales
6. tal:block
7. PHPTALES
1. path:
2. Conditional statements
3. string:
4. php:
5. not:
6. exists:
7. default
8. structure
9. Expression chains
6. PHP Integration
1. Constants
2. Configuration methods
3. class PHPTAL
4. interface PHPTAL_Filter
5. interface PHPTAL_Trigger
6. interface PHPTAL_TranslationService
1. method setLanguage(...)
2. method useDomain($domain)
3. method setVar($key,$value)
4. method translate($key)
5. method setEncoding($encoding)
7. Working with gettext
1. Creating the translation directory structure
2. Portable Object files
3. Translation Domain
4. PHP usage in PHPTAL
5. Variable interpolation
8. Creating custom expression modifiers
7. A. Note for system administrators
8. B. Useful links
9. C. Greetings
http://phptal.org/manual/en/ Page 1 of 23
PHPTAL Manual 28/04/2009 11:31
Introduction
PHPTAL is an implementation of the excellent Zope Page Template (ZPT ) system for PHP . PHPTAL
supports TAL, METAL, I18N namespaces.
PHPTALES is the equivalent of TALES, the Template Attribute Language Expression Syntax. It defines
how XML attribute values are handled.
As PHPTALES is similar to TALES, it should be easy to port python TAL templates into PHP ones (and
vice versa).
PHPTAL is freely distributed under the LGPL license, it is developed by Laurent Bedubourg
<lbedubourg@motion-twin.com> and maintained by Kornel Lesi!ski.
XML /HTML templates exist to separate logic from presentation in web services. This separation brings
more than one accompanying benefit.
better maintainability
Most template systems uses <? ?> , <% %> or <xxx:yyy></xxx:yyy> tags to find their sections. It
allows easier template system development but doesn't really help template designers.
TAL hides most of its logic in XML attributes, preserving syntax and strucutre of XHTML . This allows
previewing of TAL templates in web browser (WYSIWYG editors, live previews) and doesn't break HTML
syntax highlighting in programmers' editors.
If you have already worked with a simple template system, then you must have encountered
something looking like:
<table>
<%loop myarray as myitem %>
<tr>
<td><% myitem %></td>
</tr>
<%/loop%>
</table>
The above code will render correctly with the sample text in normal web browser, so you can present
it to your clients even if the code required to get 'myarray' values doesn't yet exist.
Another big advantage of PHPTAL is that you benefit from more than 3 years of Zope community
experience, documentation, examples, and help. PHPTAL relies on this community to provide its users
a great deal of useful information.
Installation
PHPTAL is released as a PEAR package (see http://pear.php.net). You can download the PHPTAL
library on the PHPTAL website (http://phptal.motion-twin.com).
http://phptal.org/manual/en/ Page 2 of 23
PHPTAL Manual 28/04/2009 11:31
Once installed, you can upgrade PHPTAL easily on each PHPTAL update using PEAR :
If you do not use PEAR or do not have it installed on your system, you can still install PHPTAL by
unzipping the downloaded archive.
This will install the PHPTAL.php file and the associated PHPTAL folder in /path/to/your/lib/folder.
First example
To get a first impression of PHPTAL usage, a simple example is better than many words.
Your template is a valid xml/html document (with a root element). Here's a file named
'my_template_file.xhtml'.
<?xml version="1.0"?>
<html>
<head>
<title tal:content="title">
Place for the page title
</title>
</head>
<body>
<h1 tal:content="title">sample title</h1>
<table>
<thead>
<tr>
<th>Name</th>
<th>Phone</th>
</tr>
</thead>
<tbody>
<tr tal:repeat="person people">
<td tal:content="person/name">person's name</td>
<td tal:content="person/phone">person's phone</td>
</tr>
<tr tal:replace="">
<td>sample name</td>
<td>sample phone</td>
</tr>
<tr tal:replace="">
<td>sample name</td>
<td>sample phone</td>
</tr>
</tbody>
</table>
</body>
</html>
In php, you just have to include the PHPTAL library, and maybe configure a few variables to customize
the template system.
<?php
require_once 'PHPTAL.php';
http://phptal.org/manual/en/ Page 3 of 23
PHPTAL Manual 28/04/2009 11:31
If you execute the PHP script, you will obtain something similar to what follows.
<?xml version="1.0"?>
<html>
<head>
<title>The title value</title>
</head>
<body>
<h1>The title value</h1>
<table>
<thead>
<tr>
<th>Name</th>
<th>Phone</th>
</tr>
</thead>
<tbody>
<tr>
<td>foo</td>
<td>01-344-121-021</td>
</tr><tr> <td>bar</td>
<td>05-999-165-541</td>
</tr><tr> <td>baz</td>
<td>01-389-321-024</td>
</tr><tr> <td>quz</td>
<td>05-321-378-654</td>
</tr>
</tbody>
</table>
</body>
</html>
PHPTAL doesn't care much about line breaks and indentation in files it reads and generates. If you
want source code of generated HTML files to be pretty (with line breaks and perfect indentation), then
you might need to postprocess it with HTML Tidy.
Table of Contents
1. Attribute priority
2. TAL namespace
1. tal:define
2. tal:condition
3. tal:repeat
4. tal:omit-tag
5. tal:replace
6. tal:content
7. tal:attributes
1. Optional attributes
8. tal:on-error
3. METAL namespace
1. metal:define-macro
2. metal:use-macro
3. metal:define-slot
4. metal:fill-slot
4. I18N namespace
1. i18n:translate
2. i18n:attributes
3. i18n:name
4. XHTML in translations
5. PHPTAL namespace
1. phptal:debug
2. phptal:cache
1. Instant refreshing
2. Limitations:
3. phptal:tales
6. tal:block
7. PHPTALES
1. path:
2. Conditional statements
3. string:
4. php:
5. not:
6. exists:
7. default
8. structure
9. Expression chains
This section describes TAL and its extensions. It mainly targets template designers but must be read
by PHP integrators as well.
Attribute priority
It is important to note that the order of declaration of attributes is irrelevant.
http://phptal.org/manual/en/ Page 4 of 23
PHPTAL Manual 28/04/2009 11:31
For example,
1. define
2. condition
3. repeat
4. content or replace
5. attributes
6. omit-tag
TAL namespace
1. tal:define
2. tal:condition
3. tal:repeat
4. tal:omit-tag
5. tal:replace
6. tal:content
7. tal:attributes
1. Optional attributes
8. tal:on-error
tal:define
This attribute defines one or more variables which may be used later in the template.
You may also use tal:define with other attributes, it will be executed before any other attributes.
In above examples, the span tag won't show up because it has no printable content nor attributes.
Even the last example does not show the message because the 'hello' variable grabs it.
but the following is irregular because tal:define will calculate the content of the node before being
executed and tal:content IS the content of the node. Whatever is inside the span is just ignored.
Thus hello won't be defined and an exception will be thrown.
In above examples, you may have spotten the 'global' keywords before some variables names. In
PHPTAL you can either define a variable globally or locally.
A global variable will be accessible from any XML node of your templates or called macros.
http://phptal.org/manual/en/ Page 5 of 23
PHPTAL Manual 28/04/2009 11:31
On the contrary, a local variable is only available inside the tag it is defined in:
tal:condition
The entity and its content will be shown only if the condition is evaluated to true.
<span tal:condition="identified"> Welcome member ... </span>
If the PHP backend does not provide your templates with enough methods, you will often have to fall
back to PHP for special conditions:
This may put too much logic inside the template and it is sometimes preferable to provide boolean
attributes or accessible methods to the template:
<span tal:condition="cart/hasMoreThanFiveItems">...</span>
<span tal:condition="fullfillNumerousItems">...</span>
tal:repeat
This attribute handles iterable objects like arrays, associative arrays, and objects implementing the
PHP5 Iterable class.
The repeat attribute repeats its element and its content until the end of the specified resource.
Within a loop, you can access the current loop information (and that of its parent for nested loops)
using specific repeat/* paths.
The most common usage of tal:repeat is in using some SQL database result. The following code
will work if playersRanking contains object that implements PHP 's Iterator interface:
<table>
<thead>
<tr>
<th>Position</th>
<th>Player</th>
<th>Score</th>
</tr>
</thead>
<tbody>
<tr tal:repeat="ranking playersRanking">
<td tal:content="ranking/position"/>
<td tal:content="ranking/player"/>
<td tal:content="ranking/score"/>
</tr>
</tbody>
</table>
tal:omit-tag
This attribute asks the PHPTAL parser to ignore the entity's open and close tag, its content will still be
http://phptal.org/manual/en/ Page 6 of 23
PHPTAL Manual 28/04/2009 11:31
This attribute asks the PHPTAL parser to ignore the entity's open and close tag, its content will still be
evaluated.
<span tal:omit-tag="condition">
if the condition is true, then only this text will appear and span open and close will be removed
</span>
Will produce:
only this text will appear, span open and close will be removed
This attribute is useful when you want to create element optionally, e.g. hide a link if certain condition
is met.
If you want element that is never output, you can use tal:block
<tal:block tal:repeat="x php:range(1,10)">only this text will appear, ten times.</tal:block>
tal:replace
This attribute will replace the entire tag with a value, or by nothing if no value is given.
<span tal:replace="string:this beautyful string">
this ugly string and span
</span>
Will produce:
this beautyful string
tal:replace can also be used to create samples in source templates, but remove them from final
output.
<table>
<tr tal:repeat="item myresult">
<td tal:content="item">item value</td>
</tr>
<tr tal:replace="">
<td>sample 1</td>
</tr>
<tr tal:replace="">
<td>sample 2</td>
</tr>
</table>
tal:content
This attribute replaces the tag content with the evaluation of its expression.
<span tal:define="myvar string:my string"/>
<span tal:content="myvar">will be replaced</span>
Will produce:
<span>my string</span>
tal:attributes
$somelink->href = "http://www.google.com";
$somelink->title = "google search engine";
$somelink->text = "the google search engine";
Will produce:
<a href="http://www.google.com"
title="google search engine">the google search engine</a>
Semicolon (; ) separates attributes. If you want semicolon to be output in an attribute, you have to
double it (;; ).
The php: modifier will be explained later, basically if the line is odd then tr will have a class attribute
with "odd" as value, otherwise, no class will be set.
The "condition ? then : else " is a regular PHP expression which must be used with care but
has proven to be useful on more than one occasion.
http://phptal.org/manual/en/ Page 7 of 23
PHPTAL Manual 28/04/2009 11:31
A better way to achieve the same result would be to ask your PHP coder to create a custom modifier
for your needs (see PHP integration / custom modifiers) which would be used as follows:
Optional attributes
If you use TALES alternatives in tal:attributes and use nothing (or NULL in php) as last
alternative, attribute won't be added at all if there's no value for it (this avoids adding empty
attributes):
... tal:attributes="title object/tooltip | nothing">
XHTML attributes like selected , checked , etc. are properly handled automatically.
Remember that XHTML is case-sensitive, so SELECTED attribute is an error in XHTML . Use selected .
tal:on-error
This attribute replaces the tag by the tal:on-error expression evaluation if a path error is detected
in the tag content, or if any PHP exception is thrown in the tag content.
<span tal:on-error="string:No username defined here"
tal:content="user/name">the user name here</span>
If an error occurs accessing 'name' or 'user', the error string will be shown at the tag's place.
METAL namespace
1. metal:define-macro
2. metal:use-macro
3. metal:define-slot
4. metal:fill-slot
METAL stands for 'Macro Extension for TAL'. This namespace, supported by PHPTAL , allows template
designers to define and call XML /XHTML macros.
metal:define-macro
This attribute declares a macro. Think of macros as library of small templates which can be reused in
any other template.
<div metal:define-macro="main_menu">
<ul>
<li><a href="/">home</a></li>
<li><a href="/products">products</a></li>
<li><a href="/contact">contact</a></li>
</ul>
<div>
Last modified:
<span tal:content="mdate">page modification date</span>
</div>
</div>
Macros inherit from the caller's dictionary. In the above example, the variable 'mdate' depends on the
template that calls the macro.
metal:use-macro
This attribute calls a macro and includes its result in the current template.
<span
tal:comment="main_menu template requires 'mdate' variable"
tal:define="mdate page/last_modified"
metal:use-macro="main_menu"
/>
You can refer to external macros defined in other templates by specifying the template source file.
<span metal:use-macro="site_macros.xhtml/main_menu"/>
http://phptal.org/manual/en/ Page 8 of 23
PHPTAL Manual 28/04/2009 11:31
It is interesting to note that you can also use the PHPTAL inline replacement feature inside the use-
macro attribute value:
<span metal:use-macro="${design}/site_macros.xhtml/main_menu"/>
Macro can call itself. This way you can output arrays recursively:
<ul metal:define-macro="show-list">
<li tal:repeat="item list">
<tal:block tal:condition="php:is_array(item)" tal:define="list item" metal:use-macro="show-list" />
<tal:block tal:condition="php:!is_array(item)" tal:content="item" />
</li>
</ul>
metal:define-slot
Slots can be replaced by caller template with some custom dynamically-generated XML /XHTML .
Slots can be thought of like reverse includes, a macro can be an entire page and slots customize this
page depending on the URL. For instance, a slot may contain the latest news in the home page or
user actions when the member is logged in.
<span metal:define-slot="news_place">
<table>
<tr tal:repeat="item php:latestNews()">
<td tal:content="item/value">news description</td>
</tr>
</table>
</span>
The above example defines a place called 'news_place' which can be overwritten by caller templates.
See next section for the continuation of this example.
metal:fill-slot
This explicitly tells PHPTAL to replace a defined slot with the content provided inside the metal:fill-
slot attribute.
Slots give the opportunity to define really customizable and reusable page templates with a simple
push technology.
I18N namespace
1. i18n:translate
2. i18n:attributes
3. i18n:name
4. XHTML in translations
Note: 'i18n' is a short name for 'internationalization'. This namespace allow template designers to
specify some text zones that must be translated during template evaluation.
i18n:translate
This attribute defines some text part that must be translated using PHPTAL 's translation system.
<div i18n:translate="string:welcome_message">Welcome here</div>
In the above example, PHPTAL will looks for a translation key named 'welcome_message' and will
replace the content of the tag with the equivalent in currently requested language.
This usage is a little different, no translation key is given, thus PHPTAL will use the content of the tag
'Welcome here' as the translation key. This is a regular translation if translation system knows the key
'Welcome here'.
If no translation is found, the key will be used as the translation result. That's why using readable
message instead of keys may be a good choice.
Please note that the key to translate may be contained in a variable, to allow dynamic key selection.
http://phptal.org/manual/en/ Page 9 of 23
PHPTAL Manual 28/04/2009 11:31
i18n:attributes
Defines which attributes should be translated. Takes semicolon-separated list of attributes and keys
similar to those for i18n:translate .
<img i18n:attributes="alt 'picture alternative text';title thetitle" alt="Picture" title="${thetitle}" />
i18n:name
Translations may contain ${xxx} strings where "xxx " is the name of a variable that needs to be
interpolated dynamically.
The value of this variable will be set to the tag and its content. If you don't need tag around the value,
use tal:replace instead of tal:content . tal:omit-tag may help if the value is a concatenation
of strings.
<span i18n:name="myVar" tal:content="some/path"/>
<!-- <span>${some/path}</span> -->
<span i18n:name="myVar">foo</span>
<!-- <span>foo</span> -->
<div i18n:translate="">
Welcome <span i18n:name="user" tal:replace="user/name"/>,
you have <span i18n:name="mails" tal:replace="user/nbrMails"/>
unread mails.
</div>
PHPTAL will replace ${user} with ${user/name} and ${mails} with ${user/nbrMails} in
translation.
More information about I18N with PHPTAL is available in the PHP section of this book.
XHTML in translations
By defaults translations are assumed to contain only text, so PHPTAL escapes all "<" characters.
As of 1.1.14 you can use structure keyword in i18n:translate to disable escaping and use
translated text as-is:
Gives:
<div><b>bold text</b></div>
Caveats: This will only work in simplest cases – TAL attributes inside translated strings are ignored. Ill-
formed XHTML in translations will break page well-formedness.
PHPTAL namespace
1. phptal:debug
2. phptal:cache
1. Instant refreshing
2. Limitations:
3. phptal:tales
These attributes are not defined in TAL specifications, but are useful when working with PHPTAL .
phptal:debug
This attribute toggles the activation of PHPTAL debugging for the content of the tag it is defined in.
Note
http://phptal.org/manual/en/ Page 10 of 23
PHPTAL Manual 28/04/2009 11:31
To debug errors in macros called across templates you need to add phptal:debug in
template which defines the macro, not the one which uses it.
The debug mode stores information like filename and source line number in the template, so
exceptions thrown by incorrect path access will contain more information about where they where
thrown.
<html>
<head>
...
</head>
<body>
<div id="menu">
...
</div>
<div id="leftPane" phptal:debug=""
tal:comment="this div seems buggy, keep
trace of where errors are thrown">
...
</div>
</body>
</html>
phptal:cache
This attribute causes output of entire element (including its tag) to be cached on disk and not re-
evaluated until cache expires.
Note
Use of cache is beneficial only for elements that use very complex expressions,
macros from external files or PHP expressions/objects that access the database.
Otherwise uncached templates will be just as fast.
Content of this attribute is a duration (how long element should be kept in cache) written as number
with 'd ', 'h ', 'm ' or 's ' suffix.
<div class="footer" phptal:cache="3h">...</div>
Duration can be followed by optional "per " parameter that defines how cache should be shared. By
default cache is shared between all pages that use that template. You can add "per url " to have
separate copy of given element for every URL.
<ol id="breadcrumbs" phptal:cache="1d per url">...</ol>
<ol> will be cached for one day, separately for each page.
You can add "per expression " to have different cache copy for every different value of an
expression (which MUST evaluate to a string). Expression cannot refer to variables defined using
tal:define on the same element.
<ul> will be cached for 25 minutes, separately for each object ID.
Instant refreshing
Instead of clearing cache, it might be a better idea to put version or last modification timestamp in the
per parameter. This will cause cached template to be refreshed as soon as version/timestamp
changes and no special cache clearing will be neccessary.
Limitations:
phptal:cache blocks can be nested, but outmost block will cache other blocks regardless of
their freshness.
phptal:tales
This attribute allows us to change the behaviour of PHPTALES . The default behaviours is to interpret
attribute expressions in a very ZPT way. But sometimes you just would like to have PHP there, and
you end up using php: modifier everywhere.
Another problem concerning PHPTALES is the way PHPTAL has to interpret paths. For example,
myobject/mymethod/property/10/othermethod/hashkey takes relatively long to interpret (but
don't worry about this too much – don't optimize until you find that it is really a problem with
performance!)
PHPTAL has (at runtime) to take myobject and discover that it is an object; find out that 'mymethod' is
a method of this object (rather than a variable), and then to call it; explore the result to determine that
it is an object with a property; find that its value is an array; find the 'ten' element of this array, and
http://phptal.org/manual/en/ Page 11 of 23
PHPTAL Manual 28/04/2009 11:31
determine that it is an object; decide that othermethod is a method of this object (rather than a
variable), and get the result of its execution; find that it is an object, and then retrieve the value for the
key 'hashkey'.
Of course this was an extreme example and most of the time we don't care, because the process is
fast enough. But what if this very long path is called inside a big tal:repeat ? D'oh! phptal:tales
can help us here:
<html>
<body>
<table phptal:tales="php">
<tr tal:repeat="myobject document.getChildren()">
<td
tal:content="myobject.mymethod().property[10].otherMethod().hashkey"></td>
</tr>
</table>
</body>
</html>
Please note that the above example does the same as:
<html>
<body>
<table>
<tr tal:repeat="myobject php:document.getChildren()">
<td
tal:content="php:myobject.mymethod().property[10].otherMethod().hashkey"></td>
</tr>
</table>
</body>
</html>
tal:block
tal:block is a syntactic sugar for elements which contains many TAL attributes which are not to be
echoed.
<tal:block define="myvar string:Some value"/>
Another example:
<tal:block condition="someCondition" repeat="item someRepeat">
<div metal:use-macro="x"/>
</tal:block>
PHPTALES
1. path:
2. Conditional statements
3. string:
4. php:
5. not:
6. exists:
7. default
8. structure
9. Expression chains
PHPTALES is the expression syntax used inside tal, metal, PHPTAL attributes. From above examples,
you should have seen some PHPTALES examples (string:, php:, not:, ...). This chapter describes the
usage of PHPTALES in templates.
The value of a TAL attribute may contain more than one expression (ex: tal:define ), in which case
each expression must be separated from the next one with a '; ' character.
path:
This is the default modifier used in TAL expression when no other modifier is specified.
http://phptal.org/manual/en/ Page 12 of 23
PHPTAL Manual 28/04/2009 11:31
Inside the template or inside expression strings, you can refer to a context variable using its path in
the form ${path/to/my/variable}
<h1>${document/title}</h1>
<span tal:replace="string:welcome ${user/name},
this page has been readed ${page/countRead} times"/>
Conditional statements
As '<' and '>' should be removed from attribute expression. PHPTAL provides some equivalent good
old text-comparison operators.
These statements will mostly appear in tal:condition attributes, and in php: expressions.
string:
Because expressions are separated by a ';' character, and because '$' marks the start of a path, you
must use:
';; ' when you want to insert a real ';' character in a string,
'$$ ' when you want to insert a real '$' character in a string.
<span tal:replace="string:this is a $$100 page"/>
string:foo $bar baz <!-- will replace $bar -->
string:foo $$bar baz <!-- no interpolation -->
string:foo ; php:doFoo() <!-- two different expressions -->
string:foo ;; php:doFoo() <!-- only string -->
php:
This expression evaluates what follows as a regular PHP expression except that '->' are replaced by
dots '.' and variable names does not need to be prefixed with a dollar '$' sign.
A dot '.' separated from the rest of expression by spaces is assumed to be a concatenation sign.
php:htmlentities(foo)
php:'string ${varReplaced}'
php:'string ${some.path().to[0].var}'
php:NOT foo OR (bar GT baz)
php:a + b
php:array('a', 'b', 'c')
php:range(0, 90)
php:foo . a.b.c(e) . htmlentities(SomeClass::staticMethod())
php:SomeClass::ConstOfClass
php:SomeClass::$staticVar
php: should be used with care and won't be needed in 80% of your templates but sometimes you will
need to invoke some special PHP method to be certain whether a user is logged in, or to retrieve
specific complex data depending on some conditions, dynamically inside the template.
not:
This expression is a boolean one, useful in tal:condition statements.
<span tal:condition="not: logged">not logged</span>
exists:
This expression returns true if the path specified after it exists, and false otherwise. It is analogous
to PHP 's isset() .
Normally using a path which doesn't exist throws an error like "Cannot find variable 'foo ' in current
scope". Thus, uncertain paths must be checked first:
<span tal:condition="exists:user/preferences" tal:content="user/preferences">
Use user/preferences here if defined
</span>
default
This is not an expression but a keyword, allowing template designers to keep the content of a tag as
an alternative value if an error occurs, or if something is not defined.
http://phptal.org/manual/en/ Page 13 of 23
PHPTAL Manual 28/04/2009 11:31
Above examples introduce the '| ' character that allows the definition of alternatives for defines or
prints.
structure
This is not an expression modifier but a keyword.
While printing variables inside PHPTAL templates, you will have noticed that PHPTAL encodes each
variable to ensure the validity of the output document.
Sometimes, you may use HTML /XML variables which must be echoed as is.
<h1 tal:content="structure document/title"/>
<span tal:replace="structure document/content"/>
Expression chains
An expression chain is a list of expressions separated by '| ' characters.
While evaluating expressions separated by '| ', PHPTAL will stop its evaluation when an expression
value is not null and no error was raised while evaluating the expression.
As a string: expression is always true, string: always terminates an expression chain whatever
expression may follow.
You can use php: expressions inside expression chains, like any other expression.
<h1 tal:content="page/title | page/alternativeTitle | php:get_default_title()" />
PHP Integration
Table of Contents
1. Constants
2. Configuration methods
3. class PHPTAL
4. interface PHPTAL_Filter
5. interface PHPTAL_Trigger
6. interface PHPTAL_TranslationService
1. method setLanguage(...)
2. method useDomain($domain)
3. method setVar($key,$value)
4. method translate($key)
5. method setEncoding($encoding)
7. Working with gettext
1. Creating the translation directory structure
2. Portable Object files
3. Translation Domain
4. PHP usage in PHPTAL
5. Variable interpolation
8. Creating custom expression modifiers
This section is aimed at PHP developers and explains how to use and customize PHPTAL behaviours
for simple and advanced usage.
PHPTAL : the main PHPTAL class. It is used to load and execute templates.
PHPTAL_TranslationService : for replacing the built-in gettext support with your own
internationalization system.
Constants
After the inclusion of PHPTAL library, some defines will be created in PHP context, all these defines
come from PHPTAL.php file:
http://phptal.org/manual/en/ Page 14 of 23
PHPTAL Manual 28/04/2009 11:31
PHPTAL_VERSION : version of PHPTAL library installed on your system (in format: X.X.X)
In older versions of there were constants for configuration. They have been replaced with methods.
Configuration methods
PHPTAL tries to use best defaults possible and you shouldn't need to change any of the settings.
All of these are methods of the PHPTAL class. set* methods return instance of their class, so you can
chain them:
<?php
echo $phptal->setPhpCodeDestination('/tmp/phptal')->setOutputMode(PHPTAL::XML)->setTemplate('tpl.zpt')->execute();
?>
setEncoding(encoding) : Specify what encoding your templates use. The default is UTF -8 .
setOutputMode(mode) : If given PHPTAL::XHTML (the default), will output elements like <img> ,
<link> , and attribtes like checked , selected according to XHTML specification, including
HTML compatibility guidelines. Use PHPTAL::XML if you want to output other XML formats, like
Atom or RSS .
This doesn't mean all your files need to be in the root directory, you can use sub folders to
organize your template designer's work. It's just a shortcut which will allow you to reference
templates without specifying the real path, but instead their relative path within the repository.
setForceReparse(boolean) : forces reparsing of all templates all the time. This slows down
PHPTAL very much, it should be used only for testing and debugging. Never enable this on
production servers.
There are other set* methods for filters, internationalisation, etc. They have been described in other
sections of this manual.
class PHPTAL
This is the main library class for you to use.
You can perfectly well choose to specify the template source after setting context variables.
http://phptal.org/manual/en/ Page 15 of 23
PHPTAL Manual 28/04/2009 11:31
<?php
...
$tpl = new PHPTAL();
// it is a matter of taste but you can use the set() method instead of
// setting context using PHPTAL::__set() like above
$tpl->set('title', 'my title');
$tpl->set('values', array(1,2,3,4));
$tpl->set('user', new User('Joe'));
$tpl->setTemplate('mytemplate.xhtml');
...
?>
You can also decide to use a generated string as the template source instead of using an existing
template file:
<?php
$src = <<<EOS
<html>
<head>
<title tal:content="title">my title</title>
</head>
<body>
<h1 tal:content="title">my title</h1>
</body>
</html>
EOS;
require_once 'PHPTAL.php';
$tpl = new PHPTAL();
$tpl->setSource($src);
$tpl->title = 'this is my title';
try {
echo $tpl->execute();
}
catch (Exception $e){
echo $e;
}
?>
In the above example, because PHPTAL requires a template source idenfifier (usually the template file
realpath), PHPTAL will use the md5 of the $src parameter as a unique identifier. You may decide to
force the identifier using a second setSource() argument:
<?php
$src = <<<EOS
<html>
<head>
<title tal:content="title">my title</title>
</head>
<body>
<h1 tal:content="title">my title</h1>
</body>
</html>
EOS;
require_once 'PHPTAL.php';
$tpl = new PHPTAL();
// because the source is contained in this file and won't be modified unless
// this file is modified, it is 'faster' to specify __FILE__ as the unique
// source identifier, thus no md5 of $src will be done on each call.
$tpl->setSource($src, __FILE__);
$tpl->title = 'this is my title';
try {
echo $tpl->execute();
}
catch (Exception $e){
echo $e;
}
?>
interface PHPTAL_Filter
This interface allows you to automatically filter templates sources (pre-filters) or PHPTAL result (post-
filters).
Pre filters are invoked before the template parsing and won't be invoked until the source template file
is modified.
http://phptal.org/manual/en/ Page 16 of 23
PHPTAL Manual 28/04/2009 11:31
You can set only one pre-Filter and one post-Filter using set* Filter. If you have more than one filter to
chain, you can wrap them into a single class, implementing the PHPTAL_Filter interface, which
would invoke the filter's chain.
<?php
require_once 'PHPTAL.php';
interface PHPTAL_Trigger
The phptal:id attribute was added into the PHPTAL for the PHP5 version to replace the old
PHPTAL_Cache interface and to abstract it a little more.
When a phptal:id is reached, PHPTAL will look in its triggers list for a matching id and will invoke the
trigger start() and end() methods before entering the element, and just after it.
If your trigger wants the element and its content to be executed, you'll have to return
PHPTAL_Trigger::PROCEED .
The PHPTAL_Trigger::end() will be called after the element (whether it has been executed or not).
This allows you to build cache systems using ob_start() in start() and ob_get_contents(),
ob_end_clean() in end().
<html>
...
<div>
...
foo bar baz <span tal:replace="id"/> foo bar baz
...
</div>
...
</html>
For some reason we decide the div block requires to be cached. We introduce a phptal:id into the
template:
<html>
...
<div phptal:id="somePossiblyUniqueKeyword">
...
foo bar baz <span tal:replace="id"/> foo bar baz
...
</div>
...
</html>
Then we write our trigger which will cache the div content:
<?php
require_once 'PHPTAL.php';
require_once PHPTAL_DIR.'PHPTAL/Trigger.php';
http://phptal.org/manual/en/ Page 17 of 23
PHPTAL Manual 28/04/2009 11:31
$f = fopen($this->_cachePath, 'w');
fwrite($f, $content);
fclose($f);
}
private $_cachePath;
private $_usedCache;
}
?>
The key here is to return from start() with either SKIPTAG or PROCEED .
When SKIPTAG is returned, PHPTAL will just ignore the tag and call end(). This usually means that the
trigger takes the hand in deciding what to show there.
When PROCEED is returned, PHPTAL will execute the tag and its content as usual, then call end(). This
allows our cache class to play with output buffers to execute the tag once and to store the result in a
file which will be used in later calls.
<?php
require_once 'PHPTAL.php';
require_once 'CacheTrigger.php'; // our custom trigger
$tpl->id = 1;
echo $tpl->execute();
?>
You can add as many triggers as you like to your templates. A generic cache trigger may also handle
more than one phptal:id ... etc...
interface PHPTAL_TranslationService
1. method setLanguage(...)
2. method useDomain($domain)
3. method setVar($key,$value)
4. method translate($key)
5. method setEncoding($encoding)
PHPTAL comes with a default gettext translation service, as shown in another section. For some
reason you may prefer to implement your own service of translation.
http://phptal.org/manual/en/ Page 18 of 23
PHPTAL Manual 28/04/2009 11:31
method setLanguage(...)
This method may be called by the template to change the current output language.
Its arguments are a list of possible languages (use func_get_args() to get the argument array). The
first known language should be used by your service.
<?php
require_once PHPTAL_DIR.'PHPTAL/TranslationService.php';
method useDomain($domain)
If you decided to store your translations into separate files, one for each application, for example, this
method allows you to select the translation domain from your templates (i18n:domain ).
<?php
require_once PHPTAL_DIR.'PHPTAL/TranslationService.php';
The above example is a possible translation solution where keys are stored in PHP files which return
an associative array of key => translation.
method setVar($key,$value)
This method matches i18n:name calls. It builds an interpolation context for later translate calls.
<?php
require_once PHPTAL_DIR.'PHPTAL/TranslationService.php';
method translate($key)
The last and most important method to implement, it asks your service to translate the specified key
for the currently selected language.
<?php
require_once PHPTAL_DIR.'PHPTAL/TranslationService.php';
http://phptal.org/manual/en/ Page 19 of 23
PHPTAL Manual 28/04/2009 11:31
return $value;
}
...
}
?>
method setEncoding($encoding)
PHPTAL class calls this method to inform your translation service what encoding is used by the
template. translate() method should return strings in that encoding. If you always use the same
encoding for templates and translation files (i.e. UTF-8), you can leave this method empty.
gettext is a standard GNU internationalization / translation system which can be used with PHP and
which is supported by PHPTAL .
The usage of gettext is simple but you will have to perform some tests to be sure everything works
fine on your system.
First, PHP must be compiled with the --with-gettext flag. See PHP documentation for how to do
this.
if (!function_exists("gettext"))
{
echo "gettext is not installed\n";
}
else
{
echo "gettext is supported\n";
}
The PHP gettext extension requires a specific structure which will contain your translation files.
/path/to/your/translation_root/en_US/LC_MESSAGES/
/path/to/your/translation_root/en_GB/LC_MESSAGES/
/path/to/your/translation_root/fr_FR/LC_MESSAGES/
/path/to/your/translation_root/es_ES/LC_MESSAGES/
... and so on ...
The language code is composed of two characters defining the language itself (en, fr, es, ...) and two
characters defining the country (US, GB, FR, ES, ...).
msgid ""
msgstr ""
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
This command won't work if you don't have gettext tools installed on your system.
This will produce a MO file (machine object) indexing your translation for quick access.
http://phptal.org/manual/en/ Page 20 of 23
PHPTAL Manual 28/04/2009 11:31
Translation Domain
The domain is matched against your translation file names. In above examples we used 'mydomain'
as domain name.
You can have more than one domain for the same application, it can enhance gettext's performance
to split your application translations in more than one file.
try {
$tr = new PHPTAL_GetTextTranslator();
// set language to use for this session (first valid language will
// be used)
$tr->setLanguage('en_GB.utf8', 'en_GB');
Variable interpolation
# french
msgid "welcome"
msgstr "Bienvenue ${name} vous avez recu ${n} messages !"
Because i18n:translate contains a value 'welcome', the template data will be ignored and the
message given by gettext will be used instead.
These modifiers are defined by ZPT specifications but PHPTALES can be extended with your own
modifiers to manipulate strings, date, money numbers, objects, whatever...
The aim of a modifier is to return some PHP code that will be included in the template PHP source.
Modifiers are used at parse time. If you change the behaviour of a modifier, you'll have to delete
generated PHP files and reparse all templates using it.
http://phptal.org/manual/en/ Page 21 of 23
PHPTAL Manual 28/04/2009 11:31
Please note that modifiers produce code, and mustn't echo data!
The src argument will be "my/path/value ", and the $nothrow boolean will be false, because
tal:replace requires the path to be fully resolvable.
An expression like:
<span tal:replace="some-modifier: my/path/value | other/path"/>
some-modifier: with "my/path/value" as $src argument and $nothrow set to true because an
alternative exists
path: with "other/path" as $src, and $nothrow set to false because in case the alternative is not
found, tal:replace will be in trouble.
Remember, path: is the implicit modifier used when no other modifier is specified.
Modifiers can use other modifiers to generate simpler php code. The example below shows this.
//
// This modifier will return a money formated string (XXX.XX)
//
// usage:
//
// money: path/to/my/amount
//
// this modifier uses phptal_tales() function to generate the
// PHP code that will return the value of the modifier argument.
//
// in the example:
//
// money: path/to/my/amount
//
// the produced code will be something looking like:
//
// sprintf("%01.2f", phptal_path($ctx->path, "to/my/amount"))
//
// This code will be included right into the template where needed.
//
// @param string $src
// The expression string
// @param string $nothrow
// A boolean indicating if exceptions may be throw by phptal_path if
// the path does not exists.
// @return string
// PHP code to include in the template
//
function phptal_tales_money( $src, $nothrow )
{
// remove spaces we do not require here
$src = trim($src);
return 'sprintf("%01.2f", '.phptal_tales($src, $nothrow).')';
}
By default PHPTAL will use the system's temp directory (via PHP 's sys_get_temp_dir() function if
available) or will try to guess where it should be, /tmp on Unix like systems and c:\windows\temp
on Microsoft ones, to store the compiled templates. The default destination can be changed to your
liking by calling setPhpCodeDestination() method with the appropriate path. Be it the system's
temp directory or a custom one, it needs to have its permissions setup as to allow the PHP running
process (the Apache user if using mod_php or the cgi/fastcgi user otherwise) to create and update
files in that directory.
PHPTAL creates one file for each different template file and one file for each tag if using
phptal:cache . It doesn't create separate files for macros (which are simply compiled as PHP
functions inside the compiled template file). These files are automatically cleaned up once in a while,
more specifically, each time a template is compiled there is random probability, controlled by
setCachePurgeFrequency() method, which will just delete files older than set by
setCacheLifetime() method.
http://phptal.org/manual/en/ Page 22 of 23
PHPTAL Manual 28/04/2009 11:31
Alternatively you can also schedule the deletion of old/unused files by running this from an Unix-like
shell (e.g. in a cron job):
find /tmp/ -name tpl_\* \( -atime +1 -o -mtime +14 \) -exec rm -v {} \;
Appendix C. Greetings
Big thanks goes to:
Olivier Parisy, the first enthusiastic PHPTAL user and bug finder,
http://phptal.org/manual/en/ Page 23 of 23