Page 1 of 3

HTML Templating class for PHP - Please try it /give feedback

Posted: Tue Jun 24, 2003 3:41 pm
by Jim_Keller
Hey everyone,

While working on a rather large PHP project, I decided to incorporate some simple HTML templates so as to separate my HTML from my PHP. I wrote a very basic parser, but it kept growing and growing, and has now become a fully functional templating class that seems to be working quite well. I haven't researched what other tools are out there (though I'm sure there are at least a few), but I'd be interested in hearing feedback / bug reports about the one I've written. Please check it out at:

http://jim.centerfuse.net/HTML_Template/

Both the documentation and code are still in beta stages, but I'd be interested in hearing any constructive criticisms you may have.

-Jim Keller

Posted: Tue Jun 24, 2003 4:23 pm
by Heavy
I'm currently developing one too. I gave your system a quick look, and I like the format of the control tags <[CONTROL_KEYWORD]>.
Neat.

Maybe I'll dig into it some day, to see what I think about it.

Check out http://www.yapter.com

Posted: Tue Jun 24, 2003 7:48 pm
by McGruff
Smarty http://smarty.php.net/ seems to be well regarded although I haven't used it myself.

I haven't been coding all that long and I'd be interested to learn what the advantages of using a template engine could be.

I appreciate that its good design to keep the html out of the php but I don't quite get the point of regex-parsing templates rather than simply including a html template in the php and, in the html template, jumping into <?php to echo a var - thus avoiding all the parsing.

Of course it gets more complicated if you have dynamic, repeating items - like an unknown number of posts in a forum topic - but the principle is pretty much the same. In this case I'd maybe include another template in a loop to build a $posts var containing all of the posts, and then echo that in the topic html template along with the other vars.

Template engine code Loops and IF/ELSES seem to blur the desired clean separation of html and php slightly. An html designer has to take a small step into the scripting realm which might seem trivial to programmers but may not be so easy for a designer.

I recently had to explain to a client how to echo php vars in html templates. That was OK but even some simple template engine code could have created difficulties.

Posted: Wed Jun 25, 2003 3:04 am
by Heavy
You can probably get any web designer to understand:

Code: Select all

<[BLOCK emailtable]>
  <table>
  <tr><td>Name</td><td>email</td></tr>
  <[BLOCKLOOP emailtable]>
    <tr><td><[VAR name]></td><td><[VAR email]></td></tr>
  <[/BLOCKLOOP emailtable]>
  </table>
<[/BLOCK emailtable]>
But may get problems if you want to teach them:

Code: Select all

<?php if (isset($ArrEmailTable)){?>
  <table>
  <tr><td>Name</td><td>email</td></tr>
  <?php foreach ($ArrEmailTable as $EmailTableRow){?>
    <tr><td><?php echo $EmailTableRow['name'];?></td><td><?php echo $EmailTableRow['email'];?></td></tr>
  <[/BLOCKLOOP emailtable]>
  </table>
<?php }?>
Note to admin: The PHP end tags (question mark and greater than) does not show in the code above
In addition to this. You can let any end user put some HTML in a parsed template, since you can check for forbidden tags and such. It gets a bit messier when allowing plain php code in the template.

Speed:
Parsing is of course slower than plain script code. I plan to do some caching in my engine so that overhead is minimized. The cache files are probably just as fast as plain php code templates.

Other Templates

Posted: Wed Jun 25, 2003 9:40 am
by Net_Monkey
Heavy wrote:Speed:
Parsing is of course slower than plain script code. I plan to do some caching in my engine so that overhead is minimized. The cache files are probably just as fast as plain php code templates.
I ended up developing my own template class before I knew about resources like Smarty and such. I ended up just improving on my own rather than re-working all my apps to work with a different class. One thing I have included that I have yet to see in any other template system (though I think Smarty may have this capability now) is the functionality to process and include SSI information in the template.

Since work (and my personal sites) uses SSI to get all the navigation menus included, it became a necessity and it's extremely useful.

Pete
http://www.superscripts.net

Posted: Wed Jun 25, 2003 9:48 am
by []InTeR[]
Hi Jim, be more carefull with information on the net...
Does 'Greycourt Road' tells you anything?

Got it from you Resume.

Posted: Wed Jun 25, 2003 3:22 pm
by McGruff
Heavy wrote:You can probably get any web designer to understand:

..etc (code with control structures)
I agree that custom code tags would be easier to work with in the example you gave - but should control structures appear anywhere in an html template at all? I'd be inclined to avoid it by including separate, mini-templates for recursive items in the php script. Php handles all the issets and loops, html templates just echo vars and format the output.

Posted: Wed Jul 02, 2003 10:25 am
by RacerX
Pardon my ignorance, but isn't this the same as using include()? Also, does anyone here use Fusebox? It seperates the 'design' into a global template. Maybe I am off base here 8O

Posted: Thu Jul 03, 2003 7:40 am
by Heavy
What about templating form elements?

If you like to have a system where for example checkboxes depend on each other, lets say:
* permission to read check box
* permission to write check box
It makes sense to have some javascript automation among those boxes.
*if write is not set and then clicked and read is not set then set read aswell.
*if read is set and clicked and write is set then clear write aswell.
I would like to template these things with php and let the designer do just:

Code: Select all

<HTML>
    <HEAD>
        <&#1111;TEMPLATE_JS chkFunctions]>
    </HEAD>
    <BODY>
        <&#1111;CHECKBOX readChk; &#1111;...ordinary html parameters...] ]>
        <&#1111;CHECKBOX writeChk; style="whatever" onclick="annoyingPopupOrWhatever()" title="check to allow user to change content"]>
    </BODY>
</HTML>
...and catch the designers onclick to execute it before or after my required hooks on the checks.
In this case, you need templates that are more than just includes.

Still, I like the thought about includes, because it's faster than parsing parsing parsing.

Maybe what I'll find optimal is "light templates" or something like that.

Posted: Thu Jul 03, 2003 2:08 pm
by jason
My opinion about Template in PHP sway all the time. Right now, I am on the "they are good for x reasons" side of the fence.

However, I don't know of any templating engines that do templating right.

Unfortunately, this is the case with this template engine here as well. Now, just quickly, I should point out that I have developed a template engine as well, because, well, all the ones I have seen (including Smarty) fail the "Visual Designer" test. If I can't pull a template into a visual designer and accurately see the result, the template fails. The designer might as well use XSL.

This is the case here as well.

Take the sample provide:

Code: Select all

&lt;&#1111;BLOCK emailtable]&gt;
  &lt;table&gt;
  &lt;tr&gt;&lt;td&gt;Name&lt;/td&gt;&lt;td&gt;email&lt;/td&gt;&lt;/tr&gt;
  &lt;&#1111;BLOCKLOOP emailtable]&gt;
    &lt;tr&gt;&lt;td&gt;&lt;&#1111;VAR name]&gt;&lt;/td&gt;&lt;td&gt;&lt;&#1111;VAR email]&gt;&lt;/td&gt;&lt;/tr&gt;
  &lt;&#1111;/BLOCKLOOP emailtable]&gt;
  &lt;/table&gt;
&lt;&#1111;/BLOCK emailtable]&gt;
A visual editor (such as dreamweaver) could not accurately display this template.

First, I don't know if the visual editor would munge with the funky tags.

However, a bigger problem (and the same one Smarty suffers from, is the variable printing problem.

Code: Select all

&lt;&#1111;VAR name]&gt;
tells me that it will print a var named name. But this is not good, because when I put this into a template, and then try to view the template, I won't see a thing. So I can visually style my document. {header} would be better here for variables that would be displayed. That way, I can see, visually, the style as I am creating the template.

Simply, XML based templates, or those that try to act like them, are bad for designers. Designers don't design using XML, they design visually. Programming create these templating engines with the thought of what THEY think designers need.

Compare the above with a sample template from my templating engine below.

Code: Select all

&lt;!-- INCLUDE header --&gt;
&lt;table&gt;
	&lt;caption&gt;
		&lt;!-- IF &#123;userIsLoggedIn&#125; --&gt;
			&lt;b&gt;User logged in.&lt;/b&gt;
		&lt;!-- ELSE IF &#123;userStatus&#125; eq 'active' --&gt;
			&lt;b&gt;User status is active&lt;/b&gt;
		&lt;!-- ELSE --&gt;
			User not logged in.
		&lt;!-- END IF --&gt;
	&lt;/caption&gt;
&lt;!-- LOOP ON people FOR EACH family --&gt;
&lt;!-- &#123;debug&#125; --&gt;
	&lt;tr&gt;
	&lt;!-- LOOP ON family FOR EACH name --&gt;
		&lt;td&gt;
			&#123;ifEmpty; name.first,No First Name&#125;
			&#123;!makeBold;name.last&#125;
		&lt;/td&gt;
	&lt;!-- END LOOP --&gt;
	&lt;/tr&gt;
&lt;!-- END LOOP --&gt;
&lt;/table&gt;
&lt;!-- INCLUDE footer --&gt;
The example above works well for a visual designer. They can create this template using common things. For example, if they used Dreamweaver MX, they could simple create a simple template, and from design view, type in the tag they want. The comments are all block level elements.

The power in the class is also the ability to modify these, so if you didn't want to use LOOP ON, you could instead use LOOPON, or just LOOP, however your designers wanted.

The ability to Cache is handled seperatly (as it should be), but easily done.

Functions and extensions are easy to create. The difference between the two is subtle, yet important. An extension actually builds what is displayed. For example, here is the ifEmpty extension:

Code: Select all

<?php
function extension_ifEmpty ( $args )
{
	list($var, $default_value) = explode(_CT_EXTENSION_VARIABLE_SEPERATOR, $args);
	$var = CerealTemplateCompiler::compile_var_names($var);
	$return_code = "<?php echo (empty($var) ? '$default_value' : $var); ?>";
	return $return_code;
}
?>
Where as, with a function, it merely calls a function which returns a value. !makeBold is such an example. {!makeBold; name.first}, when compiled, looks like this:

Code: Select all

<?php echo makeBold($name['first']); ?>
Of course, this templating engine also allows you to do this:

If you need, you could also pass multiple arguments to the function (or extension) as well.


McGruff: The prime benefit of not using PHP as you templating engine is security. As soon as you allow PHP into a template, you allow access to a wide array of functionality. With a template, you can control that.

Even in a work environment, where everyone is working at the same company, designers and programmers, preventing access to PHP from the designers is a good thing. A designer can't come along, and include bad PHP code. One thing I am doing with my template engine is a syntax checker. It won't create the file if the syntax is wrong, which goes a step to self-checking.

Using PHP as your template engine means if a designer forgets something, or makes a syntax mistake, and uploads the template, it is ready, and run, and can cause problems. Whereas if a designer uploads a template, and the template won't compile because the syntax is wrong, it means the compiled version is still okay, and the site runs normally.

Other reasons are fairly obvious. If you look around at most of the popular programs, PHP or not, most include some sort of skinning mechanism. They all do this using their own 'templating' system.' Even phpBB runs off a templating engine.

There are people who don't think non-PHP templates are a good idea (and truth be told, I was one of them), however, they are better than PHP in many cases.

Another case is when you are hosting a service for people to use. If you want people to be able to customize the interface, PHP is NOT the way to go. Take a checkout for an online credit card processor. Each merchant needs to send their customers to the processor to get checked out. However, the merchant wants to customize the header and the footer of the site. PHP is way to insecure to let them going mucking around with PHP. A template engine again is needed.

It's not the holy grail or a sliver bullet, but it's better to know when template engines are useful, and when they aren't.

Posted: Fri Jul 04, 2003 9:06 am
by sjon
Probably the only templating engine I "really" like...

php-templates



Sjon.

Posted: Fri Jul 11, 2003 3:00 pm
by ik
For me i is extremely interesting issue. I have started from creating very easy engine - "active": i.e. it is HTML including PHP calls for <?=$ThisPage->Draw("smth")?> function or general short calls i.e. <?=$SESSION["page"]?> for page title. Preprocessor makes the rest...

Than I found a beutiful Larry Ulman book and learnt that template should be passive with {smth} inclusions. Well, it was very easy to move my template to this standard via associative array ("item"=>"func for eval").

But when I did so I realized that "active" template more flexible and allows more easily include (just with include("form.htm") inside Draw() method) sub-templates. If you take preprocessor job for itself - you should add second run for this inclusion. So I came back to my first scheme.

I understand that passive template with more or less standard notation would be more universal - it could use for example with server script other than PHP. But from other hand - is it generally a good way to take on your own script a job which preprocessor should do? Actually it is a mixed way: use "passive template", change all items for code inclusions from above mentioned array, then save file as temporary, include it to script and delete in last script line. But it looks some stupid...

Posted: Fri Jul 11, 2003 3:26 pm
by ik
Some additional comments about templates. Yes, universal notation like {navbar} is good - by reasons people already mentioned here - it.s much better that variable name, becuse doesn't related to any particular script. But combination {KEY} isn't unique - {} can exist in style definition and JavaScript. So probably it would be better to use smth like {!KEY!}. Using of comments IMHO looks worse

The another simple way - use named anchor tag with name as template key. Possible addvantages:
1. It's unigue.
2. It dont use non-HTML elements
3. Anchor tag is using almost as it should - to check particular place at the page.

Posted: Fri Jul 11, 2003 3:33 pm
by Heavy
ik wrote:Actually it is a mixed way: use "passive template", change all items for code inclusions from above mentioned array, then save file as temporary, include it to script and delete in last script line. But it looks some stupid...
I would use a template form that involves no PHP for security. Then I would let the template system parse it to generate a php script that I save to disk. Let's call it a "cached template". Then, if no changes have been made to the "template" I just run the cached template instead. That could be pretty fast and flexible.

An alternative to that "update check" could be that it never checks, but instead you have to trigger the generation of a cached template yourself as an admin. Then it gets even faster. It becomes just an ordinary inclusion, and the template still does not contain any php code.

Posted: Fri Jul 11, 2003 3:56 pm
by ik
jason wrote: Compare the above with a sample template from my templating engine below.

Code: Select all

<!-- INCLUDE header -->
<table>
	<caption>
		<!-- IF &#123;userIsLoggedIn&#125; -->
			<b>User logged in.</b>
		<!-- ELSE IF &#123;userStatus&#125; eq 'active' -->
			<b>User status is active</b>
		<!-- ELSE -->
			User not logged in.
		<!-- END IF -->
	</caption>
<!-- LOOP ON people FOR EACH family -->
<!-- &#123;debug&#125; -->
	<tr>
	<!-- LOOP ON family FOR EACH name -->
		<td>
			&#123;ifEmpty; name.first,No First Name&#125;
			&#123;!makeBold;name.last&#125;
		</td>
	<!-- END LOOP -->
	</tr>
<!-- END LOOP -->
</table>
<!-- INCLUDE footer -->
The example above works well for a visual designer. They can create this template using common things. For example, if they used Dreamweaver MX, they could simple create a simple template, and from design view, type in the tag they want. The comments are all block level elements.
It looks pretty good. But the general question is remaining. If you use in template smth more than simple placeholder identifiers and use scripting with varibles, loops and other flow control conctructs - why don't use just PHP instead? Why <!--LOOP - END LOOP--> is better then <?php while{} ?>?