PHP Toolbox Code
Brought to you by:
aii
| File | Date | Author | Commit |
|---|---|---|---|
| apidoc | 2010-03-28 | aii | [r1] |
| lib | 2010-03-28 | aii | [r1] |
| sample | 2010-03-28 | aii | [r1] |
| test | 2010-03-28 | aii | [r1] |
| CHANGES | 2010-03-28 | aii | [r1] |
| INSTALL | 2010-03-28 | aii | [r1] |
| LICENSE | 2010-03-28 | aii | [r1] |
| README | 2010-03-28 | aii | [r1] |
| README.html | 2010-03-28 | aii | [r1] |
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<TITLE>PHP/Toolbox#2</TITLE>
<style type="text/css">
<!--
dir { background-color: #EEEEEE}
-->
</style>
</HEAD>
<BODY bgcolor="#ffffff">
<h1><FONT FACE="Arial">PHP/Toolbox#2 </FONT></h1>
<h2 ALIGN="JUSTIFY"><FONT FACE="Arial">What’s new?</FONT></h2>
<P ALIGN="JUSTIFY">The most important thing, new in Second Edition (#2) is <B>RETRO</B><SUP>®</SUP>—
PHP/Toolbox proprietary template processing technology. All related snippets
are made to use it to generate HTML contents. So, a new core snippet, <FONT FACE="Courier New">CRenderer,</FONT>
is included, and a few new features are added to existing #1 snippets as well.
See CHANGES for more details.</P>
<P ALIGN="JUSTIFY"><I>Note that due to these changes #2 is not 100%-compatible
with #1; the latter should not be treated as obsolete or deprecated though:
it’s still supported and will be maintained but, probably, will not be further
developed.</I></P>
<h2 ALIGN="JUSTIFY"><FONT FACE="Arial"><a name="RETRO">Why RETRO</a><SUP>®</SUP>?</FONT></h2>
<P ALIGN="JUSTIFY">One of the important problems in the web application development
is a complexity of the mixed HTML and program codes that increase as a power
of complexity of application. So, a well-known paradigm of separation the
program from HTML and template-based generation of the resulting HTML document
is reasonably recognized as a very important or even central feature of web-application
development toolbox.</P>
<P ALIGN="JUSTIFY">The PHP/Toolbox#1 is still quite useful to embed generated
snippets into existing HTML code. The <FONT FACE="Courier New">/test</FONT>
code examples or <FONT FACE="Courier New">/samples</FONT> applications demonstrates
this approach quite clearly. For example, it’s a usual practice to construct
the snippet, say, table or menu, include HTML template and then just render
the snippet where needed:</P>
<DIR>
<P><FONT FACE="Courier New"><?php<BR>
$menu = new CTTextMenu(…);<BR>
include (“sample.html”);<BR>
?></FONT></P>
</DIR>
<P ALIGN="JUSTIFY">While sample.html is:</P>
<DIR>
<P><FONT FACE="Courier New"><html><BR>
<body><BR>
<table><tr><BR>
<B><?php $menu->render() ?><BR>
</B></tr></table><BR>
</body><BR>
</html></FONT></P>
</DIR>
<P ALIGN="JUSTIFY">Again, this approach is quite useful, because it often requires
only a single line of the code to be inserted into HTML template. Moreover,
your web-designer can easily edit this template with his preferred HTML editor,
even WYSIWYG one.</P>
<P ALIGN="JUSTIFY">However, such a technique allows you to easily handle HTML
‘frame’ around snippet, but not the codes that the snippet itself generates.
The problem of the snippet design customization can be partly solved by providing
the CSS styles to any generated HTML elements, so that almost any attributes
of their visual representation can be controlled; meanwhile, their <I>structure</I>
cannot. The latter is possible only by subclassing the snippet and change
its default behavior as one needs; however, it definitely requires the <I>manual
</I>coding of the HTML generation within miscellaneous subclass methods.</P>
<P ALIGN="JUSTIFY">From this point of view, it’s probably would be quite convinient
to provide the template for each snippet <I>itself</I> as well as we provide
it for the whole page, for instance. Well, there are a lot of PHP template
engines, more or less powerful, that can be possibly used for this purpose.
However, they are all based on the common principle — a template file
with some text ‘macros’ is read, line by line, and these macros are expanded
by template engine <I>written in PHP. </i></P>
<P ALIGN="JUSTIFY">Ok, this is just fine but let’s remember that PHP <I>itself</I>
is actually a sort of ‘template engine’, just because it allows (and even
<I>requires</I>) to embed the PHP codes into HTML source. So, what we really
get is a template engine built over another template engine! Sounds a bit
cumbersome? Really, is it <I>efficient</I>? If we are already basing our development
on a rather good and powerful ‘template’ mechanism, what do we need another
for? </P>
<P ALIGN="JUSTIFY">In short, I decided to see, is another solution possible? The
answer is probably ‘yes’ and it’s rather obvious — a simple<FONT FACE="Courier New">
include()</FONT> statement manages its work just fine. Really, why <FONT FACE="Courier New"><?php
print($VARIABLE)?></FONT> is much worse than, say, <FONT FACE="Courier New">{VARIABLE}</FONT>?
Simply a bit longer? Then, what about <FONT FACE="Courier New"><?php while($CONDITION):?></FONT>
against something like <FONT FACE="Courier New"><!-- BEGIN CONDITION_loop
--></FONT>? Frankly, I can’t find a great difference…</P>
<P ALIGN="JUSTIFY">On the other hand, it’s not absolutely clear, <I>how</I> we
can utilize this mechanism for our purposes. In particular, how to force it
to co-operate with OOP-based Tbox snippets nature?</P>
<P ALIGN="JUSTIFY">Fortunately, the PHP development team in its wisdom gives us
such an opportunity. The point is that <FONT FACE="Courier New">include()
</FONT>statement can happen anywhere in the PHP program code, even inside
the function. This means that (beside other things) it should operate in <I>local
context</I> of that function. This way, we can easily provide co-operation
between the snippet’s methods and implementing templates with namespace isolation!</P>
<P ALIGN="JUSTIFY">So, ‘<B>RETRO</B>’ stands for ‘<B>R</B>eally <B>E</B>fficient
<B>T</B>emplate <B>R</B>endering <B>O</B>perations’. Note, I didn’t say <I>Fast</I>,
but <I>Efficient</I> instead. Why? Just because there is at least one really
<I>fast</I> rendering method using something like <FONT FACE="Courier New">str_replace()</FONT>
function. However, is it really <I>efficient</I>? I’m afraid not: while it
allows fast substitution of variable references, it doesn’t allow branching,
looping, etc at all. At the same time, usual PHP template engines that make
the latter possible are rather complex and large to be compiled and executed
quickly; in any case things should go harder than PHP input scan itself!</P>
<h2 ALIGN="JUSTIFY"><FONT FACE="Arial">Using RETRO<SUP>®</sup></FONT></h2>
<P ALIGN="JUSTIFY">The heart of <B>RETRO</B> technology is <FONT FACE="Courier New">CRenderer
</FONT>snippet. It’s documented quite well in <FONT FACE="Courier New">/apidoc,
</FONT>so we just observe its main programming patterns below.</P>
<P ALIGN="JUSTIFY">The renderer is isolated from the conventional snippets to
provide an opportunity to specify some common rendering details in one place.
Next, as its usual clients are snippet objects, it supports the features for
that foremost. </P>
<h3 ALIGN="JUSTIFY"><FONT FACE="Arial">Example 1</FONT></h3>
<DIR><FONT FACE="Arial"> </font>
<P><FONT FACE="Courier New"><?php<BR>
$test_object->class = “test-object”;<BR>
$test_object->TITLE = “The Test”;<BR>
$test_object->BODY = “The quick brown fox jumps over the lazy dog”;<BR>
<BR>
$r = CRenderer();<BR>
$r->render($test_object);<BR>
?></FONT></P>
</DIR>
<P ALIGN="JUSTIFY">The template file should be located at <FONT FACE="Courier New">html/test-object.html:</font></P>
<DIR>
<P><font face="Courier New, Courier, mono"><html><BR>
<head><BR>
<title><?=$THE->TITLE?></title><BR>
</head><BR>
<body><BR>
<h1><?=$THE->TITLE?></h1><BR>
<p><?=$THE->BODY?></p><BR>
</body><BR>
</html></font></P>
</DIR>
<P ALIGN="JUSTIFY">Note that:</P>
<UL>
<P ALIGN="JUSTIFY">
<P ALIGN="JUSTIFY">
<LI>You can often use ‘short’ PHP syntax that is even more compact;</LI>
<p></P>
<P ALIGN="JUSTIFY">
<P ALIGN="JUSTIFY">
<LI>All variable references are <I>local</I>; you should use <FONT FACE="Courier New">global</FONT>
directive to access global namespace;</LI>
<p></P>
<P ALIGN="JUSTIFY">
<P ALIGN="JUSTIFY">
<LI>‘<FONT FACE="Courier New">$THE</FONT>’ variable is used to refer to the
rendered entity; it often improves readability as well;</LI>
<p></P>
<P ALIGN="JUSTIFY">
<P ALIGN="JUSTIFY">
<LI>Default template location is ‘<FONT FACE="Courier New">html</FONT>’ directory
and default extension is ‘<FONT FACE="Courier New">.html</FONT>’; </LI>
<p></P>
<P ALIGN="JUSTIFY">
<P ALIGN="JUSTIFY">
<LI>By default, <FONT FACE="Courier New">CRenderer</FONT> uses passed entity’s
‘<FONT FACE="Courier New">class</FONT>’ field to locate the template for
it; if the field does not exist or entity is not an object then ‘<FONT FACE="Courier New">default</FONT>’
template is used;</LI>
<p></P>
<P ALIGN="JUSTIFY">
<P ALIGN="JUSTIFY">
<LI>All defaults can surely be overridden.</LI>
<p></P>
</UL>
<h3 ALIGN="JUSTIFY"><FONT FACE="Arial">Example 2</FONT></h3>
<P ALIGN="JUSTIFY">The <FONT FACE="Courier New">CRenderer’s render()</FONT> method
can also accept the <FONT FACE="Courier New">array</FONT> of entities:</P>
<DIR>
<P><FONT FACE="Courier New"><?php<BR>
$test_object_1->class = “test-object”;<BR>
…<br>
</FONT><FONT FACE="Courier New"> $r = CRenderer();<BR>
$r->render(array($test_object_1, …));<BR>
?></FONT></P>
</DIR>
<P ALIGN="JUSTIFY">The template below produces a list of partial headers followed
by paragraph texts:</P>
<DIR>
<P><FONT FACE="Courier New"><h1><?=$THE_KEY?>: <?=$THE->TITLE</h1><BR>
<p><?=$THE->BODY?></p></FONT></P>
</DIR>
<P ALIGN="JUSTIFY">Looks like not very useful? Well, how about the following?</P>
<h3 ALIGN="JUSTIFY"><FONT FACE="Arial">Example 3</FONT></h3>
<DIR><FONT FACE="Arial"> </font>
<p><FONT FACE="Courier New"><?php<BR>
$r = CRenderer();<BR>
$r->render(do_query(<br>
</FONT><FONT FACE="Courier New">“select ’test-object’ as
class, TITLE, BODY from para”<br>
</FONT><FONT FACE="Courier New">)</FONT><FONT FACE="Courier New">);<BR>
?></FONT></p>
</DIR>
<P ALIGN="JUSTIFY">The <FONT FACE="Courier New">render()</FONT> method can also
accept the PHP resource #, so template file like above produces formatted
content of a whole table from database!</P>
<h3 ALIGN="JUSTIFY"><FONT FACE="Arial">Example 4</FONT></h3>
<P ALIGN="JUSTIFY">At last, you can render simple scalar variable as well as an
object: given the script from the 1<SUP>st</SUP> example, template file located
at <FONT FACE="Courier New">html/test-object.html</FONT>, would contain:</P>
<DIR>
<P><FONT FACE="Courier New"><html><BR>
<head><BR>
<title><?=$THE->TITLE?>::<?=$THE_KEY?></title><BR>
</head><BR>
<body><BR>
<h1><?=$THE->TITLE?></h1><BR>
<?$this->render($THE->BODY, “test-body”)?><BR>
</body><BR>
</html></FONT></P>
</DIR>
<P ALIGN="JUSTIFY">and sub-template <FONT FACE="Courier New">html/test-body.html</FONT>
would be like this:</P>
<DIR>
<P><FONT FACE="Courier New"><p><?=THE?></p></FONT></P>
</DIR>
<P ALIGN="JUSTIFY">This way, it’s possible to control sub-templates flexibly.</P>
<h2 ALIGN="JUSTIFY"><FONT FACE="Arial">Pros & Contras of #2</FONT></h2>
<P ALIGN="JUSTIFY">The main difference of #2 and #1 branches is almost completely
hidden from a common user. They both have all workhorse snippets pre-cooked;
their overall throughputs are almost the same. At the same time #2 is much
more flexible and might be more complex to dig in. On the other hand, it allows
to customize the HTML ouput much more easily: it means, say, that it provides
much more powerful theming support. </P>
<hr>
<small><address>
(C) Alexey Ilyin <<a href="mailto:ai@a4web.com">ai@a4web.com</a>>, 2001.<br>
Home page: <a href="http://alexworld.a4web.com">alexworld.a4web.com</a>
</address></small>
</BODY>
</HTML>