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>