PHP: Template Engines
Todo mundo que programa em PHP sente falta de uma boa alternativa para separar o código PHP do visual (HTML). Nessas horas vale a pena estudar algumas template engines para PHP disponíveis para saber qual que melhor se adapta à suas necessidades e projeto. Alguns frameworks MVC possuem sua própria engine, outros tentam.
O mais famoso e usado como inspiração por muitos outros projetos. Robusto (possuindo blocos condicionais/loops e várias funções próprias) e rápido (“compilando” suas páginas para arquivos PHP).
<ul>
{foreach from=$myArray item=foo}
<li>{$foo}</li>
{/foreach}
</ul>
$smarty = new Smarty;
$arr = array(1000, 1001, 1002);
$smarty->assign ('myArray', $arr);
$smarty->display ('HelloWorld.tpl');
Com esta engine saímos de um problema e entramos em outro, é necessário aprender (lembrar) algumas palavras reservadas para sinalizar variáveis, além do uso dos limitadores das expressões.
<html>
<head>
<title>{tmpl_var name='title_text'}</title>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
</head>
<body>
<p>{tmpl_var name='body_text'}</p>
</body>
</html>
$tmpl = new vlibTemplate('tmpl/basic.htm');
$tmpl->setvar('title_text', 'TITLE: This is the vLIB basic example ...');
$tmpl->setvar('body_text', 'BODY: This is the message set using setvar()');
$tmpl->pparse();
Muito pouco usual, o FXL faz uso dos blocos de comentário HTML para definir os loops. Outros semelhantes e nada melhores são: QuickSkin e XTemplate.
<table>
<!-- START row -->
<tr>
<!-- START cell -->
<td >{td_value} </td>
<!-- END cell -->
</tr>
<!-- END row -->
</table>
$fxlt = new fxl_template('example.tpl');
$fxlt_row = $fxlt->get_block('row');
$fxlt_cell = $fxlt_row->get_block('cell');
for ($tr = 1; $tr <= 3; $tr++) {
for ($td = 1; $td <= 3; $td++) {
$fxlt_cell->assign('td_value', $tr.':'.$td);
$fxlt_row->assign('cell', $fxlt_cell);
$fxlt_cell->clear();
}
$fxlt->assign('row', $fxlt_row);
$fxlt_row->clear();
}
$fxlt->display();
Mais do mesmo, mas com alterações de sintaxe.
<h1>{if:logged} Welcome {username} {else:} User not logged {end:} </h1>
<ul>
{foreach:rows,row}
<li>
{row['name']}
</li>
{end:}
</ul>
$t = new vemplator();
// if/else
$t->assign('logged', true);
$t->assign('username', 'Rogerio');
// loop
$items = array(
array('name' => 'Laptop'),
array('name' => 'Memory Stick')
);
$t->assign('rows', $rows);
echo $t->output('example.template.html');
Uma alternativa ao estilo Smarty de muitos, porém é mais confuso e segue um padrão de nomenclatura bem particular.
<table>
<tr><td>[blk.val;block=tr]</td></tr>
</table>
$TBS =& new clsTinyButStrong ;
$TBS->LoadTemplate('template.htm') ;
$list = array('X','Y','Z') ;
$TBS->MergeBlock('blk',$list) ;
$TBS->Show();
Possui como diferencial um Template Inheritance, o que facilita muito a vida na construção de templates.
<html>
<head>
<title>{block "title"}My site name{/block} </title>
</head>
<body>
<h1>{block "page-title"}Default page title{/block} </h1>
<div id="content">
{block "content"}
Welcome to my amazing homepage
{/block}
</div>
</body>
</html>
{extends "base.html"}
{block "title"}
Gallery
{/block}
{foreach $images img}
<img src="{$img.url}" alt="{$img.description}"></img>
{/foreach}
$dwoo = Dwoo();
$images = array(
array('url' => 'img1.jpg', 'description' => 'Ferrari'),
array('url' => 'img2.jpg', 'description' => 'BMW')
);
$params = array();
$params['images'] = $images;
echo $dwoo->get("gallery.tpl", $params);
Baseado no Smarty, Django Templates e Jinja (os dois últimos para Python).
<html>
<head>
<title>{{ page.title }}</title>
</head>
<body>
{{ page.content }}
</body>
</html>
$h2o = new h2o('index.html');
$page = array(
'title' => 'title of a page',
'body' => 'Hello world'
);
echo $h2o->render(compact('page'));
Entre os projetos disponíveis no PEAR (PHPLIB, Sigma e IT) esse é o melhor.
Tem como desvantagem o fato de ter que definir as propriedades da sua classe como public (pelo menos dá para trabalhar com classes), linhas de includes e configurações exageradas (não presentes no exemplo abaixo), e algumas automações que precisam ser bem explicadas senão o programador (usuário) fica doido. Além de ter que codificar muito mais linhas se compararmos com os demais exemplos.
<html>
<head>
<title>{title}</title>
</head>
<body>
<!-- o valor do input será adicionado em $element['input'] -->
Input Box: <input name="input" />
<ul>
<!-- isso é o mesmo que foreach ($numbers as $number => $string) -->
<li flexy:foreach="numbers,number,string" >
<a href="mypage.html?id={number}">{string}</a>
</li>
</ul>
<!-- chamando o método da classe -->
{someMethod()}
</body>
</html>
class controller_test {
var $title;
var $numbers = array();
var $elements = array();
function controller_test() {
$this->start();
$this->output();
}
function start() {
$this->title = "Hello World";
// create an HTML Element for the form element.
$this->elements['input'] = new HTML_Template_Flexy_Element;
$this->elements['input']->setValue('Hello');
for ($i = 1;$i< 5;$i++) {
$this->numbers[$i] = "Number $i";
}
}
function output() {
$output = new HTML_Template_Flexy();
$output->compile("home.html");
$output->outputObject($this,$this->elements);
}
function someMethod() {
return "Hello From A Method";
}
}
new controller_test();
Todos os exemplos a cima foram retirados dos próprios sites dos projetos, sofrendo alterações afim de minimizar as linhas e focar em suas caracterísicas, vantagens e desvantagens.
Em meados do ano passado comecei escrever uma engine baseada no JSF+Facelets (Java) e nesse mês voltei a trabalhar nela e espero que no próximo ano (2011) já tenha uma versão liberada (farei um post sobre).