The history of the templates.

The history of the templates.

PHP origins

As usual our php learning begins with inserting the script to the HTML page; for example it can be our own reference catalog.

<?php

$connection 
mysql_connect("localhost""user""pass");
mysql_select_db("my_database");

$result mysql_query("SELECT title FROM rubric WHERE id="intval($id));

if (
mysql_error())
    echo 
mysql_error();

else {
    echo 
"<h2>"mysql_result($result0). "";

    
mysql_free_result($result);

    
$result mysql_query("SELECT id, title, ratio, description, site_date FROM site 
WHERE rubric="
intval($id). " ORDER BY ratio DESC, site_date DESC, title");

    if (
mysql_error())
        echo 
mysql_error();

    else
        while (
$row mysql_fetch_assoc($result))
            echo 
"<b><a href=\"/redirect.php?id={$row[id]}\">{$row[title]}<br>
{$row[description]}<br><font size=\"-1\">Recorded: 
{$row[site_date]}, rating: {$row[ratio]}


"
;
}

?>

That code is very simple, but it works! Difficulties can start if you want to write the rubric name in the page header. You’ll have to create the php insertion in the >title< tag and put the code that will execute first query.

Another difficulty can appear when you work with cookies. Cookies should be used according to the rubrics that are visited by user. Let’s suppose that our homepage will be visited by thousands of people and we create the banner engine with targeting for the potential advertisers. For example, user that visited such rubrics as rock-music and instruments will see the banner that advertises electric guitars on the next page.

In that case we’ll have to insert php-code at the beginning of the file.

Code’s complication

Now we want all our pages to be written on PHP, i.e. all pages should look like the php-code. Output is carried out by means of echo (print). Here we have the subscription page. At that page user can choose the rubrics he want to subscribe at.

<?php

include "db-connect.inc";
include 
"login-check.inc";

if (!
$logged_in) {
    
header ("Location: /register.php");
    exit();
}

include 
"page-header.inc";

print(
"<h2 class="club_article_small_caption">News
<table cellpadding=\"4\" cellspacing=\"0\" border=\"0\">"
);

$result mysql_query("SELECT id, title, announce, news_date FROM news ORDER BY 
news_date DESC LIMIT 10"
);

if (
mysql_error())
    print(
mysql_error());

else
    while (
$row mysql_fetch_assoc($result))
        print(
"<tr><td>{$row[news_date]}");

        if (
$row["news_date"] > date("Y-m-d"time() - 3600*24*14))
            print(
"<font color=\"#cc0000\">new!</font>");
        
        print(
"</td><td>
        <a href=\"read.php?id={$row[id]}\"><b>{$row[title]}</b></a>
        <br>{$row[announce]}</td></tr>"
);

print(
"</table>");

include 
"page-footer.inc";

?>

That code is very complicated for reading even if we add comments. Here we can remove the announce output to the function:

<?php
...

else
    while (
$row mysql_fetch_assoc($result))
        
print_announce($row);

...
?>

There is another method of using php and HTML. PHP has such property as advanced-escaping. It allows to insert the HTML-code to the language constructions:

<?php

include "db-connect.inc";
include 
"login-check.inc";

if (!
$logged_in) {
    
header ("Location: /register.php");
    exit();
}

include 
"page-header.inc";

?><h2 class="club_article_small_caption">News</h2>
<table cellpadding="4" cellspacing="0" border="0"><?php

$result 
mysql_query("SELECT id, title, announce, news_date FROM news 
ORDER BY news_date DESC LIMIT 10"
);

if (
mysql_error())
    print(
mysql_error());

else
    while (
$row mysql_fetch_assoc($result)) {
        
?><tr><td><?=$row["news_date"]?><?php

        
if ($row["news_date"] > date("Y-m-d"time() - 3600*24*14)) {
            
?><font color="#cc0000">new!</font><?php
        
}

        
?></td><td> <a href="read.php?id=<?=$row["id"]?>">
        <b><?=$row["title"]?></b></a>
        <br><?=$row["announce"]?></td></tr><?php
}

?></table><php

include "page-footer.inc";

?>

Templates classes

Here we’ll talk about templates with blocks. You can insert chosen variables to the text template without creating the class.

For example:

-- main.tpl --
<html>
<head><title>{TITLE}</title>
</head>
<body>
{MAIN}
</body>
</html>

-- table.tpl --
<table>
{ROWS}
</table>

-- row.tpl --
<tr>
<td>{NUMBER}</td>
<td>{BIG_NUMBER}</td>
</tr>

Code:

<?php

 
/* START */

include("class.FastTemplate.php3");
$tpl = new FastTemplate("/path/to/templates");

$tpl->define( array( main => "main.tpl",
                     
table => "table.tpl",
                     
row => "row.tpl" ));


$tpl->assign(TITLE"FastTemplate Test");


for (
$n=1$n <= 3$n++)
{
    
$Number $n;
    
$BigNum $n*10;
    
$tpl->assign(array(
            
NUMBER => $Number,
            
BIG_NUMBER => $BigNum ));

    
$tpl->parse(ROWS,".row");
}

$tpl->parse(MAIN, array("table","main"));
Header("Content-type: text/plain");
$tpl->FastPrint();

exit;
?>

Output:

<html>
<head><title>FastTemplate Test</title>
</head>
<body>
<table>
<tr>
<td>1</td>
<td>10</td>
</tr>
<tr>
<td>2</td>
<td>20</td>
</tr>
<tr>
<td>3</td>
<td>30</td>
</tr>

</table>


</body>
</html>

That construction is not very convenient. Here blocks are realized by means of multiple insertion to the subordinate template variable.

Here we have another example: HTML_Template_IT class from PEAR library:

<table border>
    <tr>
        <td colspan=2>
            __global__
            <p>
            (hidden and automatically added)
        </td>
    </tr>
    <tr>
        <td>block1</td>
        <td>
            <table border>
                <tr>
                    <td colspan=2>block2</td>
                </tr>
                <tr>
                    <td>inner1</td>
                    <td>inner2</td>
                </tr>
            </table>
        </td>
    </tr>
</table>

That class knows that inner1 is the child block for block2, and there is no use to tell it about it. If you want to insert data to the block you can execute the following code

<?php
$tpl
->setVariable(...);
$tpl->parseCurrentBlock();
?>

If you want to insert the content to block1 you have to run as follows:

<?php
$tpl
->setCurrentBlock("inner1");
$tpl->setVariable(...);
$tpl->parseCurrentBlock();

$tpl->setVariable(...);
$tpl->parseCurrentBlock();

$tpl->parse("block1");
?>

As a result script will have the following view:

<?php
$tpl 
= new HTML_Template_IT( [string filerootdir] );

// template loading
$tpl->loadTemplatefilestring filename [, boolean removeUnknownVariables
boolean removeEmptyBlocks] )

// setting the variables "global", 
$tpl->setVariablestring variablenamemixed value );

// another method of indicating the variables
$tpl->setVariable( array ( string varname => mixed value ) );

$tpl->setCurrentBlockstring blockname );

// Repeat it
$tpl->setVariable( array ( string varname => mixed value ) );
$tpl->parseCurrentBlock();

// get the result or print it calling $tpl->show()
$tpl->get();
?>

XML

In PHP3 there is a module of XML processing functions. By means of functions of that module you can create your own XML-code handlers but you can’t check the propriety of the XML-document.

XML is a method of structured data recording. Structured data are e-tables, address books, configurational parameters, finance transactions etc. XML is a set of the rules for developing text formats that allow you to structure your data.

<eshop>
    <!—Categories of commodities -->
    <category id="3">
        <title>Meat products</title>

        <!—Commodities from the given category -->
        <commodity id="1">
            <title>Fish</title>
            <measure-unit> kilogram</measure-unit>
            <price>100</price>
        </commodity>
        <commodity id="3">
            <title>Meat</title>
            <measure-unit> kilogram</measure-unit>
            <price>200</price>
        </commodity>

        <!-- Subcategory -->
        <category id="15">
            <title> wastage</title>

            <commodity id="2">
                <title>Caviar</title>
                <measure-unit> kilogram</measure-unit>
                <price>10</price>
            </commodity>
        </category>

    </category>

    <category id="10">
        <title>plant products</title>

        <commodity id="5">
            <title> sunflower</title>
            <measure-unit>piece</measure-unit>
            <price>50</price>
        </commodity>
    </category>
</eshop>

So, it is the method of recording the structured data in XML. XML is a format for recording such structure; the only thing you have to do is to write tags’ names and rules.

XML is not the programming language, that’s why you don’t have to be a programmer for using it. XML allows computer creating and reading the data providing the uniqueness of the structure. XML allows to escape wide spread mistakes of language projection.

PHP developers suggest to process some elements of XML documents by php functions.

<?php
$file 
"data.xml";

// Array of the processed nodes
$map_array = array(
    
"BOLD" => "B",
    
"EMPHASIS" => "I",
    
"LITERAL" => "TT"
);

// Function for the beginning of the tag
function startElement($parser$name$attrs) {
    global 
$map_array;
    if (
$htmltag $map_array[$name]) {
        print 
"<$htmltag>";
    }
}

// Function for the end of the tag
function endElement($parser$name) {
    global 
$map_array;
    if (
$htmltag $map_array[$name]) {
        print 
"";
    }
}

// Function for the text
function characterData($parser$data) {
    print 
$data;
}

$xml_parser xml_parser_create();

// use case-folding so we are sure to find the tag in $map_array
xml_parser_set_option($xml_parserXML_OPTION_CASE_FOLDINGtrue);
xml_set_element_handler($xml_parser"startElement""endElement");
xml_set_character_data_handler($xml_parser"characterData");

// XML-file reading
if (!($fp fopen($file"r"))) {
    die(
"could not open XML input");
}

while (
$data fread($fp4096)) {
    if (!
xml_parse($xml_parser$datafeof($fp))) {
        die(
sprintf("XML error: %s at line %d",
                    
xml_error_string(xml_get_error_code($xml_parser)),
                    
xml_get_current_line_number($xml_parser)));
    }
}
xml_parser_free($xml_parser);
?>

Smarty

Smarty is one of the PHP projects. Smarty is a template class, but in practice it has more functionality than other templates have.

Smarty inserts variables to the template as well as executes php code in the template. Templates in Smarty can be transformed to the php scripts; integrated php parser fulfills all the work concerned with variables insertion to the text and executing the logic constructions. If caching is enabled these php scripts are saved in the files. When templates are changed scripts are generated once again. Such caching speeds the scripts’ working up.

Also Smarty can process integrated to the templates logic constructions if-else, transforming them to the php script. Such constructions as variable modifiers are processed analogously. They allow to remove some functions from the main script.

<h2>{$title|upper}</h2>
Topic: {$topic|truncate:40:"..."}

That text will be transformed to the following code:

<?php echo $this->_run_mod_handler("upper"true$this->_tpl_vars["Name"]); ?>

Topic: <?php echo $this->_run_mod_handler("truncate"true
$this->_tpl_vars["Name"], 40"..."); ?>

Also there can be used such integrated variables as $smarty.now.

php-templates

Template engine with medium opportunities is variables and blocks with big speed of working because it is made like a php module. To install it you have to recompile Apache on the server and write the php module to the php.ini using Windows.

Template with products and prices list:

<html>
<head>
    <title>Prices of ACME, Inc.</title>
</head>
<body>
    <table border=1 cellspacing=0 cellpadding=2>
        <tr>
            <th>Product</th><th>Price</th>
        </tr>
        <tmpl:row>
        <tr>
            <td>{product}</td><td>{price}</td>
        </tr>
        </tmpl:row>
    </table>
</body>
</html>

Code that takes them from the database and inserts to the template:

<?php

$template 
tmpl_open("prices.html");

$sql "SELECT product, price FROM Products ORDER BY product";
$result mysql_query($sql) or die("SQL error: "mysql_error());

while(
$data mysql_fetch_assoc($result)) {
    
tmpl_iterate($template"row");
    
tmpl_set($template"row"$data);
}

echo 
tmpl_parse($template);
?>

Sablotron, expat, SAX-parsers

Working with XML documents there are two methods: SAX (simple access to XML) and DOM (document object model). Method DOM is working with document using object programming interface. SAX is a data receiving with the help of parser that processes the XML document line. SAX parser can be written by you, but it is better to write it if the task is simple enough.

DOM is a specification that describes the correspondence between objects and nodes. For working with the help of DOM there are used libraries, the most famous of which is libxml. PHP has php_domxml library that includes libxml and has opportunity of creating DOM objects in PHP.

Sablotron is a XSLT processor, program that runs the XSL transformations for XML documents. Sablotron uses expat – XML SAX parser – for data accessing in the document.

In the XSLT 1.0 there is such an element as xsl:import. Transformation processor opens the XSL document indicated in the xsl:import element and adds templates from the imported document to the main document.

DOM XML

At that moment DOM is the most famous template in PHP. It has enough huge code and runs enough simple operations but still it has big perspectives.

The main advantage of DOM XML is that binary module for text processing of the document doesn’t exist in PHP. It means that you will write parser yourself.

Operations with document using DOM should be grouped to the functions; i.e. template DOM class should be created.

Separate template should include general data of the site and its issues.

<?

$root1 
$dom1->document_element();
$child $root1->child_nodes();

$root2 $dom2->document_element();

for (
$i 0$i sizeof($child); $i++)
        
$root2->append_child($child[$i]->clone_node());
?>

You can also create a simple script where queries will be directed to. Write to .htaccess as follows:

Options FollowSymLinks
RewriteEngine On

# checking whether with the same name and extension 
# phpxml exists for the root issue
RewriteCond %{DOCUMENT_ROOT}/$1/index.phpxml -f

# if such file exists rule works
RewriteRule ^([a-z0-9_/-]+)/?$ /$1/index.php

RewriteCond %{DOCUMENT_ROOT}/$1.phpxml -f
RewriteRule ^([a-z0-9_/-]+)\.php$ /composer.php [L]

In the composer.php script there will be opened file with the same name that has been requested, but it extension will be phpxml. Server Apache while processing the rules has already checked the existence of that file.

After that you have to read the file and insert its content to global template and transform it with the help of XSLT.

Documents’ validation

Now developers store the data in the files instead of storing them in the database. What are we doing working with database: we get the array and transform it to the text line. Working with file is more complicated process; you have to check the data integrity.

There are two methods of the markup creating: data-centric markup and document-centric markup.

Data-centric markup example:

<?xml version="1.0"?>
<championship-list>
<championship>
<acro>ETCC</acro>
<title>European Touring Car Championship</title>
<description>FIA-organized racing series. Uses racing cars.</description>
<site></site>
</championship>

<championship>
<acro>BTCC</acro>
<title>British Touring Car Championship</title>
<description>Analogue to ETCC, except that races take.</description>
<site>http://btcc.co.uk</site>
</championship>

<championship>
<acro>DTM</acro>
<title>Deuche Tourenwagen Masters</title>
<description>Most famous German Touring racing series. </description>
</championship>
</championship-list></no-escape>

Here we have two hierarchy levels – line + field, actually it is just the same as as a query from the database formatted with the help of sql2xml.

Document-centric markup example:

<?xml version="1.0"?>
<championship-list>
FIA organized about 20 racing servies, including 2 touring cars championships.

<championship><title>European Touring Car Championship</title> 
(<acro>ETCC</acro>) uses significantly tuned road cars, mostly BMW.</championship>

<championship>Another FIA series is <title>British Touring Car</title> 
(<acro>BTCC</acro>) is analogue to ETCC, except that races take.</championship>

Allthough, these are not the world's most famous championships.

<championship><acro>DTM</acro> (<title>Deuche Tourenwagen Masters</title>), 
the most famous Touring racing series not only in Germany.</championship>
</championship-list>

Data in the acro and title elements are the same and they can be got from the document by means of the following queries: XPath or XQuery: /championships/championship[acro='DTM']/title. First variant of the markup can be presented as a database table. It can be complicated, for example:

<championship>
<acro>DTM</acro>
<title>Deuche Tourenwagen Masters</title>
<description>Most famous German Touring racing series.</description>
<drivers>
<driver>Laurent Aiello</driver>
<driver>Bernd Schneider</driver>
<driver>Marcel Fassler</driver>
<driver>Jean Alesi</driver>
<driver>Cristian Albers</driver>
</drivers>
</championship>

Second document has more complicated structure and it can’t be put to the table.

It is the main difference between XML-databases and non-XML databases. XML-database works with document-centric markup as well. Data-centric markup can be stored in the relational database and formatted by sql2xml.

Here is another example. Markup of the form in the TXF class:

<?xml version="1.0" encoding="windows-1251"?>
<txf:form xmlns:txf="http://txf.sourceforge.net/" name="item" 
    action="category.php" receive-method="ANY" suggest-method="POST">
  <txf:rule>
    <txf:revswitch true="0">
      <txf:logic type="and">
        <txf:logic type="or">
          <txf:func name="my_email_check">
            <arg select="//txf:input[@name = "email"]/value" 
                setInvalid="//txf:func[@name = "email"]/value"/>
          </txf:func>
          <txf:trigger test="not(//txf:input[@name = "send_email"]/value)"/>
        </txf:logic>
<txf:trigger test="string-length(//txf:input[@name = "login"]/value) > 0"/>
      </txf:logic>
    </txf:revswitch>
    <txf:revswitch true="1">
      <txf:trigger test="string-length(//txf:input[@name = "login"]/value) = 0 and 
          string-length(//txf:input[@name = "email"]/value) = 0
    </txf:revswitch>
  </txf:rule>
</txf:form>

I check it with the help of DTD-scheme. Checking of the document scheme correspondence is the standard function of the DOM XML library.


 

  • Top