Re: New thread - Template base class design
| From: | Philippe Jausions | Date: | Fri, 11 Jun 2004 04:58:35 +0000 |
| Subject: | Re: New thread - Template base class design | ||
| References: | 1 | Groups: | php.pear.dev php.pear.dev |
| Request: | Send a blank email to pear-dev+get-30471@lists.php.net to get a copy of this message | ||
Greg Beaver wrote:
$tpl =& new Template(); $tpl->compiler =& new Template_Compiler_Savant(); $tpl->openTemplate('/name/of/template.html'); $tpl->setData('t', $data); $tpl->output(); I would suggest something like: <?php $tpl = &Template::create('flexy');This makes sense in the PEAR community, although that requires some serious cleanup of the current HTML_Template "directory". However, there is a need to make room for non-text-generating templates. This syntax would prevent another "flexy" template engines under Image... Not that it would be a smart naming choice, but let's keep it in mind.
$tpl->open('/name/of/template.html'); // or, $tpl->open($fp) - let it accept a file handle as well, // so that custom streams can be used, for both input filtering // and unusual filesystemsI like the fact you thought about it ;-) However, remember that the API itself (as I defined it) doesn't specify what the parameter should be: string, resource, object,...
$tpl->configure([template-specific data, in an associative array]);What would configure() do? This would need to be some generic information regardless of underlying template engine implementation and format generated... That could be a specific for PEAR templates, in this case, there should be a PEAR-standard way to do that for any packages... I think a setOption() method would better match other PEAR packages.
$tpl->set('t', $data); $tpl->output(); // or $res = $tpl->toString(); $tpl = &$tpl->create('savant'); // or $morecontrol = new Template_Foo; $morecontrol->doSomethingSpecialForFoo(); // initialize a new template from an existing sub-template $tpl = &$tpl->create($morecontrol); // etc. ?> The advantage of this design is that the user can use the pre-built templates, or pass in a custom one to leverage the code in the base class, as long as it conforms to the API expected of child classes.Fine with me ;-)
I would recommend that the assignment question be studied very carefully - Alan's method solves the extract() problem elegantly. If template variable assignment simply meant <?php $tpl = &Template::create('flexy'); $tpl->t = $data; $tpl->thing = &$refdata; ?> and the template in savant would simply reference $this->t and $this->thing. Other templates would compile so that {t} became $this->t, and so on. This would allow very straightforward management. It would mean that ALL private/protected variables would have to be prefaced with _ to avoid overwriting, but that's not a big deal.I think it's pushing the requirements of the base class a bit too much. There is a risk of being too restrictive for some other implementations of a template engine. Backward compatibility would require the __set() __get() to be working with PHP4, which is not guaranteed. Also, templates should also be editable by persons less skilled in PHP, having them require to do a $this-> for every variables may not be a good thing. Certainly enough, this comment only applies to replacement templates... From what I understood, the Flexy approach does assign values to member of an object, but not of the template itself. This allows for a stricter namespace for data. I am more conformtable with that.
resetting template variables would be as simple as:
foreach (get_object_vars($this) as $name => $val) {
if ($name{0} == '_') {
continue;
}
unset($this->$name);
}
This would need to be made a method, a user shouldn't know about the internal of a class, especially its private/protected members. Hence the "clearData()" method ;-) But maybe you were talking of its implementation?
and could be included to allow re-using a template. Implementing blocks would be very easy with this method, by instantiating a number of templates and adding them as template variables $tpl = &Template::create('IT'); $block = &$tpl->create('IT'); $block->var1 = 1; $block->var2 = 'hi'; $block->open('/path/to/block.php', 'blockname'); // optional parameter only recognized by IT, ignored by others $tpl->block1 = &$block; $tpl->open('/path/to/block.php', 'main'); This would be IT-specific and so obviously require a slight rewrite to work with a switch to another template style. One solution might be to do some magic. $tpl->open('/path/to/block.php\\main'); The basic open code would normalize all directory separators, but IT could split on the backslash, to determine which block is needed. When switching to another template, this would try to open the file "main" - it would result in an interesting directory structure, but could work.All block buildings should be encapsulated into an object. I'd like to point you to http://www.11abacus.com/dev/pear/ITInterfaced.phps for some inspiration... ;-) This means that two classes may need to be defined for this template class design, one for the template (i.e. how to put things together) and a template engine (manages data, compiler...) Because some engines don't necessary require "block building", the template class may not be directly useful. However, filters could be implemented there... This also means that some implementations of the template engines have to be ambivalent when it comes to what they accept in open(); (or openTemplate();)
In any case, the important thing is direct assignment to members of the template is probably the way to go - it's efficient, direct, and really easy to document. In PHP5, __set() could be used to validate template assignment as well, which is a neat by-product of this design choice.I disagree on that, this approach would almost likely make PHP5 mandatory... Also, in my views there are two things when it comes to templates: A template itself that describes how things are put together, and a template engine that use the template to actually generate something. -Philippe