<html>
<head>
<style type="text/css">
.example {
margin-bottom:10px;
border:1px solid #E0E0E0;
background-color:#F0F0F0;
padding:5px;
clear:both
}
h1 {border-bottom:1px solid black}
.template, .usedWidgets, .result,.generated {
color:#303030;
background-color:white;
border:1px solid black;
float:left;
margin-right:20px;
width:500px
}
.result,.generated {
margin-top:5px;
border:1px solid black;
background-color:white;
width:500px;
float:left
}
.resultCode {padding:10px}
.widget
{
margin:2px;
border:1px solid black
}
p {
padding:3px;
margin:0px;
background-color:#A0A0A0;
font-weight:bold;
font-size:16px
}
.widget p {background-color:#C0C0C0}
.firstRow , .secondRow {clear:both}
.comment {margin-bottom:20px}
.bolder,.bolder2 {font-size:14px;font-weight:bolder;}
.bolder {color:blue}
.bolder2 {color:red}
</style>
</head>
<body>
<h1>Siviglia Templating System</h1>
The Siviglia Templating System is the template engine used by the Siviglia Framework (work in process).
It was designed with the following goals in mind:
<ul>
<li><b>Intuitive</b>: It's syntax should be very intuitive.It should be usable without technical knowledge (specially, for content creators)</li>
<li><b>Reusable</b>: Templates should be composed of smaller bits ("widgets") ,which, in turn may be composed of other widgets.Those widgets may be reusable.</li>
<li><b>No need for "templating languages"</b>: Templates and widgets may use php freely, without needing of special template languages.</li>
<li><b>Different levels of abstraction</b>: From the website structure, to the smallest boxes, should be expressed by templates.</li>
<li><b>Cacheable</b>: Templates should generate code, which may be cached</li>
<li><b>Output depending on platform</b>:Given a template, and using different widget resolution paths,code for different platforms may be generated.</li>
</ul>
<br><br>
<div class="example">
<h1>Sample usage</h1>
Using the engine is easy.You'll need at least one directory to store widgets.You'll see how to code those widgets in the examples below.<br>
To include and initialize the engine, use the following code:
<div class="template">
<pre>
<?php
include_once("SivigliaTemplates.php");
$o=new CTemplateParser();
$st=& $o->solveTemplate("[_B]Hello World[/B]");
// Here you get the code generated by the engine
$code=$st->nodesToText();
// To use it right away, just eval it.
eval("?>".$code);
?>
</pre>
</div>
<div style="clear:both">
</div>
<br><br>
The <b>CTemplateParser</b> constructor accepts two parameters:
<ul>
<li>An additional array of paths for widget resolution (with higher priority than the default paths)</li>
<li>An array of paths to be used as the default widget resolution paths</li>
</ul>
<br>
The <b>solveTemplate</b> method accepts a template as a string, and returns a CTemplate object, which can
be converted to actual code using the <b>nodesToText</b> method.<br>
Usually, the string given to solveTemplate has been read from a file (or database), and the code generated by nodesToText is stored in a cache file.
<br><br>
So, including and using the class is simple.Lets look now how to write templates and widgets.<br><br>
</div>
<br>
<?php
function boldify($cad)
{
$cad=preg_replace('/(\\[(?:_|\/)[^\\]]*\\])/','<b class="bolder">\1</b>',$cad);
return preg_replace('/(\\[\:(?:_|\/)[^\\]]*\\])/','<b class="bolder2">\1</b>',$cad);
}
$tests=array(
array("template"=>"B.html",
"title"=>"Simple Template and Widget",
"comment"=>"Let's begin with a simple example.<br>The template is:<br><br><b>[_B]</b>Hello World<b>[/B]</b><br><br>This is a simple template, using a simple widget.The widget name is <b>\"B\"</b>, and will set to bold its contents.<br>
This means the templating system will look for a file named \"B.html\", located in the 'widgets' folder.<br><br>
The widget file only contains:<br><br>
<b>[_*]</b><br><br>
The tag [_*], means 'whatever the template contained within this tag'.The tag, in this case, is B.The upper-level tag for any widget, is its file name (without extension).<br>
",
"widgets"=>array("B")
),
array("template"=>"BI.html",
"title"=>"Simple template-side composition",
"comment"=>"Template side composition means you can use multiple widgets in the same template.<br>
The widgets can be used sequentially, or nested, as the contents of any tag is always re-evaluated looking for nested widgets.<br>
This template uses 2 nested widgets, B and I.You can see how the output from the widgets are combined.",
"widgets"=>array("B","I")
),
array("template"=>"WIN.html",
"title"=>"Widgets with nested subtags",
"comment"=>"A widget can have any number of nested tags.In this case, the template will have to use those tags following the structure the widget dictates.<br>
The important thing here is that, once the template uses a widget, the output will be controlled by the <b>widget</b>.<br><br>
Let's see an example, which will help to intuitively understand how it works:<br>",
"postcomment"=>"
There are a few things to understand about nested tags.<br>
<ul>
<li>All nested tags are optional.<br>The templating system will not force the presence of any nested tag.<br>In the previous example, nothing prevents the use of a <b>FLOATBOX</b> not containing any <b>[_TITLE]</b> subtag.<br></li>
<li>The same tag can appear multiple times in the widget.Each apparition of a tag in a template, is replaced in the widget in every place the tag is used (given they're at the same depth level)</li>
<li>Any tag that includes nested tags, cant use <b>[_*]</b>.If a tag has subtags, its content is constructed by the output of its subtags.<br>This means, in the previous example, that <b>FLOATBOX</b> cant have a <b>[_*]</b> tag, that it's not inside <b>TITLE</b> or <b>CONTENTS</b></li>
<li>Then, any content in the template under the scope of a tag, which has subtags, will not be processed by the widget.<br>This means, if the template uses a <b>FLOATBOX</b>, all the text that it's not inside the subtags <b>[_TITLE]</b> or <b>[_CONTENTS]</b>, will be lost when code is generated.</li>
<li>There are no restrictions in the number of times a certain sub-tag can appear in a template.<br>The associated code in the widget will be repeated as many times as the subtag appears in the template<br>This means that if a template uses 2 <b>[_TITLE]</b> tags inside a widget instance,the associated code in the widget file will be included twice.</li>
<li>In a template, the code generated for a widget is driven by the <b>widget</b> structure, not the template structure.<br>
This means that doesnt matter if the template specifies <b>[_CONTENTS]</b> before <b>[_TITLE]</b>.As the widget drives its code generation, the title will still appear first.</li>
<li>A widget can specify nested tags in two ways:
<ul>
<li> Simply by its name : <b>[_TITLE]</b>, without closing tag.<br>
In this case, the contents of this tag in the template, will be inserted there.<br>
If there's no <b>[_TITLE]</b> tag in the template, nothing will be shown.</li>
<li> Using closing tag and (optionally), <b>[_*]</b><br>
For example, <b>[_TITLE][_*][/TITLE]</b>.<br>
The <b>[_*]</b> tag will be replaced by the content specified in the template inside the [_TITLE] tag.
</li>
</ul>
Whats the difference between the two?<br>
Consider the following cases:<br><br>
Case 1: <div>[_TITLE]</div><br><br>
Case 2: [_TITLE]<div>[_*]</div>[/TITLE]<br><br>
In the first case, the div will be included in the generated code, even if the template didnt specified any <b>[_TITLE]</b> tag.<br><br>
In the second case, the div will only appear if there was a <b>[_TITLE]</b> tag in the template, acting like a condition.<br><br>
</li>
<li>You can nest tags as much as you wish, and the template must use the same nesting structure</li>
</ul>
",
"widgets"=>array("FLOATBOX")
),
array("template"=>"WIN2.html",
"title"=>"Nested subtags and nested widgets",
"comment"=>"You can seamlessly use new widgets inside terminal subtags of a parent widget.<br>Notice that nested subtags always have precendence.<br>
So, if a <b>FLOATBOX</b> widget has a <b>TITLE</b> nested tag, that tag will be used, even if there's another independent widget with the name <b>TITLE</b> (inside a TITLE.html file)<br>",
"widgets"=>array("FLOATBOX","B","I")),
array("template"=>"CONTAINER.html",
"title"=>"Widget-side composition",
"comment"=>"A very powerful feature is the ability of use widgets within widgets.<br>
To do this, just prepend <b>:</b> around nested widgets tags.<br><br>
In this way, widgets can be reused, stack different abstraction levels, and create very different outputs playing with widget inclusion paths.<br>
You can also see the recommended way of creating loops to repeat widget sub-tags, using <b>PRE</b> and <b>POST</b> dummy tags.<br>
Remember that, if a widget has nested tags, any code outside those tags in the template will be lost!<br>
To understand this, see how the html comment is lost in the following example generated code.<br><br>
You can see too how using <b>[_PRE]</b> is equivalent to using <b>[_PRE][_*][/PRE]</b>",
"widgets"=>array("BOXCONTAINER","FLOATBOX")),
array("template"=>"LINEWRITER.html",
"title"=>"PHP context resolution",
"comment"=>"One of the most powerful features of the Siviglia Templating system is resolution of php contexts, so PHP and HTML code can be safely mixed.<br>
The previous examples used just static values for tag values.But it'll be usual that you may need pass php variables, even php code, to certain tags.<br>
On the other hand, the widgets may need to use certain tags inside PHP code, for example, to initialize variables.<br
The templating system analyzes the code across the multiple template-side and widget-side nesting, and builds a new PHP code resolving the different contexts where tags are used within the templates and widgets.<br>
In the following example, look the few different ways the template is specifying the widget tag value, and the different ways the widget uses that tag.<br>
In the widget, you can also see how the same tag is used in different places in the same widget",
"postcomment"=>"In the previous example, you can see an important consecuence of having both template and widget-side nesting:<br><h3><b>All php used in the template and all widgets, is executed within the same scope</b></h3>.<br>
That means the chance of name clashing is high!All names used within widgets should be properly prefixed to avoid name clashing, specially for loop counters.",
"widgets"=>array("LINEWRITER")
)
);
include_once("SivigliaTemplates.php");
$o=new CTemplateParser('',getcwd()."/widgets");
for($k=0;$k<count($tests);$k++)
{
$current=$tests[$k];
echo '<div class="example"><h1>'.$current["title"].'</h1>';
echo '<div class="comment">'.$current["comment"].'</div>';
$content=file_get_contents("templates/".$current["template"]);
echo '<div class="firstRow">';
echo '<div class="template"><p>Template code</p>';
echo '<div class="templateCode"><pre>'.boldify(htmlentities($content)).'</pre></div>';
echo '</div>';
$st=& $o->solveTemplate($content);
$code=$st->nodesToText();
echo '<div class="usedWidgets"><p>Used widgets</p>';
for($j=0;$j<count($current["widgets"]);$j++)
{
echo '<div class="widget"><p>'.$current["widgets"][$j].' (File: widgets/'.$current["widgets"][$j].'.html)</p>';
echo '<div class="widgetCode"><pre>';
echo boldify(htmlentities(file_get_contents("widgets/".$current["widgets"][$j].".html")));
echo '</pre></div></div>';
}
echo "</div>";
echo "</div>";
echo '<div class="secondRow">';
echo '<div class="result"><p>Result</p>';
echo '<div class="resultCode">';
eval("?>".$code);
echo '</div></div>';
echo '<div class="generated"><p>Generated code</p>';
echo '<div class="generatedCode"><pre>'.htmlentities($code).'</pre></div>';
echo '</div></div>';
echo '<div style="clear:both"></div>';
if($current["postcomment"])
echo '<div class="postcomment">'.$current["postcomment"].'</div>';
echo '</div>';
}
?>
Send any comments, bug reports, feature requests to <a href="mailto:dashiad@gmail.com">dashiad@gmail.com</a><br><br>
Are you using this class? I'll be really grateful if you make me know!
</body>
</html>
|