Re: Separation of logic, design and data



Frank van Wensveen wrote:

I believe that in a perfect world the design of a website (or feature
on a website) should be totally separated from its design and the data
it serves up. I'd like some suggestions on good ways to do this,
because in the real world it can be quite difficult.

Keeping styling separate from the rest is smiple (sic): just do all your
layout, colour schemes, etc with CSS.

After that you've still got the problem of the fact that your code has to
do things in the correct order to output the page -- say, output HTML
header stuff first, then body stuff, then sidebar stuff, and finish with
some legalese and footer stuff. This can be solved using a template
engine. There are several available, though I can't say I like any of
them, I generally write my own template engine using the interface pasted
below. (Infact, I've only recently coded it as a proper PHP Interface,
earlier I used a standard class, which I would extend one or two methods
of.

This interface allows you to use (note the seemingly random order):

$t = new StdTemplate('Foo Bar');
$t->add_section('Foo', '<p>Foo</p>', 'foo',
StdTemplate::DIVISION_MAIN, 2);
$t->add_section('Bar', '<p>Bar</p>', 'bar',
StdTemplate::DIVISION_EXTRA, 3);
$t->add_section('Foo Bar', '<p>The life of Foo Bar</p>', 'foobar',
StdTemplate::DIVISION_HEAD, 1);
$t->add_script('/js/prototype.js');
$t->add_meta('Author', 'Me', FALSE, array());
$t->add_filter(new SpellCheckFilter(),
StdTemplate::DIVISION_MAIN | StdTemplate::DIVISION_EXTRA);
$t->add_section('Baz', '<p>Baz</p>', 'baz',
StdTemplate::DIVISION_EXTRA, 3);
$t->output();

which might output this:

<html>
<head>
<title>Foo Bar</title>
<meta name="Author" content="Me">
<script type="text/javascript" src="/js/prototype.js"></script>
</head>
<body>
<div id="head">
<div class="section" id="foobar">
<h1>Foo Bar</h1>
<p>The life of Foo Bar</p>
</div>
</div>
<div id="main">
<div class="section" id="foo">
<h2>Foo</h2>
<p><span class="spelling" title="Fool?">Foo</span></p>
</div>
</div>
<div id="extra">
<div class="section" id="bar">
<h3>Bar</h3>
<p>Bar</p>
</div>
<div class="section" id="baz">
<h3>Baz</h3>
<p><span class="spelling" title="Bat?">Baz</span></p>
</div>
</div>
<div id="foot">
</div>
</body>
</html>

Anyway, interface follows. Implement this interface and you'll be
happy. :-)

<?php

/**
* @author Toby Inkster <demiblog@xxxxxxxxxxxxxxxxx>
* @copyright Copyright &copy; 2007, Toby Inkster
* @license http://www.gnu.org/copyleft/gpl.html GNU General Public Licence
* @version 1.0
*/

/**
* The Template interface is a standard interface that you must implement
* if you would like to create a new template for Demiblog. In addition,
* your template class must define the following constants. (PHP does not
* allow constants to be defined within a template.)
*
* DIVISION_HEAD = 1
* DIVISION_MAIN = 2
* DIVISION_EXTRA = 4
* DIVISION_FOOT = 8
* (You may define up to four custom divisions with values 16, 32, 64
* and 128.)
* FULL_HTML = -1
*
* The StdTemplate class supplied with DemiBlog outputs a page with roughly
* the following structure (it may vary, depending on HTML flavour):
*
* <!DOCTYPE ...>
* <html>
* <head>
* <title>...</title>
* <meta ... /><!-- etc -->
* <link ... /><!-- etc -->
* <script src="..."></script><!-- etc -->
* </head>
* <body>
* <div id="page">
* <div id="head">##</div>
* <div id="body"><div id="main">##</div><div id="extra">##</div></div>
* <div id="foot">##</div>
* </div>
* </body>
* </html>
*
* where locations marked with a double-hash (##) can be filled with zero or
* more content panels. This structure should be adequate for expressing most
* site layouts and should provide enough id and class hooks to hang most CSS
* designs onto.
*
* In the case where it does not prove sufficient, you have two options:
*
* 1. Keep the existing StdTemplate, but write a filter to modify its
* output (using, for example, regular expressions). The filter
* can be attached to the existing template using its add_filter()
* method.
*
* 2. Write a new template class, implementing the Template interface.
* Use the existing StdTemplate as a guide -- simply extending the
* existing template is probably sufficient. You will probably want
* to modify the output() method.
*/
interface Template
{
/**
* Add a section to the template with a particular ID and Title. Add
* it to a particular division or divisions.
* @param string $title Title of section.
* @param string $body Body of section. This should be in the correct
* flavour of HTML. The template will not attempt to rewrite it.
* @param string $id HTML ID of section. The template will protect
* against multiple sections with the same ID.
* @param int $to_division Division(s) to add to.
* @return bool Success.
*/
public function add_section ($title, $body, $id, $to_division, $heading_level);

/**
* Filter for sections. An object with interface TemplateFilter must
* be supplied. Filters are not applied until $this->output() is called.
* @param Object $object Filter object.
* @return bool Success.
*/
public function add_filter (TemplateFilter $object);

/**
* Adds a META element to the template's document HEAD.
* @param string $name META name.
* @param string $content META content.
* @param bool $is_http_equiv Replace "name" attribute with "http-equiv".
* @param Array $more_attributes Extra attributes for META element.
* @return bool Success.
*/
public function add_meta ($name, $content, $is_http_equiv, $more_attributes);

/**
* Adds a LINK element to the template's document HEAD.
* @param string $rel LINK relationship.
* @param string $href LINK destination.
* @param string $type LINK MIME Type.
* @param Array $more_attributes Extra attributes for META element.
* @return bool Success.
*/
public function add_link ($rel, $href, $type, $more_attributes);

/**
* Adds a SCRIPT element to the template's document HEAD.
* @param string $src Script file.
* @return bool Success.
*/
public function add_script ($src);

/**
* @return bool HTML Flavour.
*/
public function get_flavour ();

/**
* @return string Finished page.
*/
public function output ();
}

/**
* The TemplateFilter interface is an interface for defining filters that
* act on templates and may modify their output. Filters can apply to the
* whole finished page, or just to specific sections within it. Examples of
* uses for filters:
*
* - Gzip finished pages.
* - Highlight search terms.
* - Expand abbreviations.
* - Remove/replace deprecated markup.
*
* The list is endless. (Well, obviously not the list above, as that has only
* four items, and certainly ends. But possible applications for output filters
* are infinite.)
*/
interface TemplateFilter
{
/**
* Determines suitability of this filter to a section, based on
* section position and ID.
* @param int $to_division Section position.
* @param string $to_division Section position.
*/
public function should_apply ($to_division, $id);

/**
* @param string $title Title to be filtered.
* @param string $body Body to be filtered.
* @return Array array(filtered title, filtered body)
*/
public function apply ($title, $body);
}

?>


--
Toby A Inkster BSc (Hons) ARCS
Contact Me ~ http://tobyinkster.co.uk/contact

.



Relevant Pages

  • Re: Email clients
    ... presumably this isn't a bug in Mail after all. ... but filters not that good (why don't they just license dspam or some ... totally sufficient, and the interface to them is very, very good). ... plugins are basically hacks against a "private" ...
    (uk.comp.sys.mac)
  • Re: Time and place in the breakout novel
    ... But I don't think the reader needs to have any understanding of how the chips ... The alien computer mind is different, so filters ... to become 'one with the Borg' again, so the interface was enhanced to overcome ...
    (rec.arts.sf.composition)
  • Re: per-interface packet filters
    ... rule, it helps to reduce CPU consumption, but makes 'ipfw show' ... A>> and with one interface to internet. ... A>> Our PFIL interface is quite ready for this, ... A> filters than the pfil API? ...
    (freebsd-net)
  • Re: Feedback on new format
    ... filters, the poor editing capabilities, and being limited to only part ... for the specific purpose of rating my own posts, ... OTOH, for the occasional user, I see a big advantage in the notification ... > such as yourself will use the interface every once in a while to rate and ...
    (microsoft.public.excel.misc)
  • Need some help with VS .NET 2003 Templates
    ... A class file, which implement Interface. ... Two Localization files. ... When I create a new project based on my template, let's say MyTemplate, ... A Class (This class should implement MyInterface1 and MyInterface2) ...
    (microsoft.public.vsnet.general)