BuscaPé, líder em comparação de preços na América Latina

Por dentro de um Template Engine

Posted by Mathias Grimm on dezembro 25, 2008 in PHP

Bem vindo mais uma vez!
Nesse artigo pretendo mostrar mais ou menos o funcionamento de um template engine (em php).
Templates Engine são utilizados para separar a camada de apresentação das demais camadas. A separação da camada de visualização permite
um web designer dar manutenção nos códigos sem a necessidade de entender de programação.
Entre outras vantagens dos templates engine está a capacidade de se fazer cache das páginas.

Alguns php template engines existentes são: Smarty, Integrated Template, PHPTAL, Savant, Sigma, TinyButStrong e vlibTemplate

Bom, na verdade os único que utilizei foi o smarty, os demais foram retirados do livro PHP PROFISSIONAL.
Desenvolvi então um template engine didático =) apenas para terem idéia do que se passa por dentro de um template engine.
Basicamente o que acontece é uma substituição de variaveis.
Meu template engine só faz 2 coisas, registra variáveis e controla labels de internacionalização.
Vou chamar meu template engine de TE de agora em diante, para facilitar. o TE tem apenas uma classe TemplateEngine.
Teremos 1 página, com labels em 2 idiomas pt_BR e en_US. Para isso teremos um arquivo chamado teste.php que será o controlador.Nela instanciaremos a classe
TemplateEngine e definiremos as variaveis.Teremos o arquivo do template e os 2 arquivos de internacionalização

Segue Abaixo o código do controlador:

  1. <?php
  2. include_once 'TemplateEngine.php';
  3.  
  4. //pt_BR
  5. $obTE = new TemplateEngine(TemplateEngine::pt_BR);
  6. $obTE->assign('name' ,'Mathias Grimm');
  7. $obTE->assign('site' ,'http://mathiasgrimm.com.br');
  8. $obTE->assign('comment' ,'Hello World!');
  9. echo $obTE->fetch('index');
  10.  
  11. //en_US
  12. $obTE = new TemplateEngine(TemplateEngine::en_US);
  13. $obTE->assign('name' ,'Mathias Grimm');
  14. $obTE->assign('site' ,'http://mathiasgrimm.com.br');
  15. $obTE->assign('comment' ,'Hello World!');
  16. echo $obTE->fetch('index');
  17. ?>

Agora vou tentar explicar um pouco.
Linha 2:Temos o include do TE,após isso,na linha 5 instanciamos o TE, que recebe como argumento o idioma que será utilizado.
Nesse caso o código escrito está primeiramente em pt_BR e em seguida em en_US, justamente para demonstrar a funcionalidade da internacionalização.
Os idiomas disponíveis estão definidos como constantes da classe TemplateEngine.
Linha 6:Estamos criando uma variavel 'nome', que estará disponível no template
Linha 9:É onde falamos ao TE para compilar o template (na verdade,no TE, essa compilacao acontece em tempo de execução). index é o nome do template
que será buscado pelo compilador.

Agora mostrarei o template (HTML) e explicarei logo abaixo:

  1. {config}index{/config}
  2.  
  3. {#name}: {$name}
  4.  
  5. {#site}: {$site}
  6.  
  7. {#comment}: {$comment}
  8.  

Linha 1: Entre as tags {config} e {/config} temos definido quem é arquivo de internacionalizacao dos labels
Linha 3: Temos a tag {#name} que será buscada no arquivo de internacionalização do idioma que está definido no momento.
Linha 3: temos a tag {$name} que conterá o valor que foi definido na linha 6 do controlador

Agora os arquivos de internacionalização:

pt_BR :

  1. name = Nome
  2. site = Site
  3. comment = Comentário

en_US:

  1. name = Name
  2. site = Site
  3. comment = Comment

Os arquivos de internacionalização são arquivos .ini .
O que está ao lado esquerdo do operador "=" é o nome do label, disponível no template como {#name} e o valor
a direita é o valor que será utilizado na compilação do template, assim como foi definido na linha 3 do template.

Segue agora o código do TE:

  1. <?php
  2. class TemplateEngine
  3. {
  4. const pt_BR = 'pt_BR';
  5. const en_US = 'en_US';
  6.  
  7. function __construct($lang)
  8. {
  9. $this->lang = $lang;
  10. }
  11.  
  12. private $arVars = array();
  13. private $lang;
  14.  
  15. function fetch($path)
  16. {
  17. $fp = fopen($path.'.phpte','r');
  18. $content = fread($fp,filesize($path.'.phpte'));
  19.  
  20. $this->fetchVars($content);
  21. $this->fetchLabels($content);
  22.  
  23. return $content;
  24. }
  25.  
  26. function assign($name,$var)
  27. {
  28. $this->arVars[$name]=$var;
  29. }
  30.  
  31. function fetchVars(&$content)
  32. {
  33. $pattern = '/\{\$.{1,}\}/';
  34. preg_match_all($pattern,$content,$arVars);
  35.  
  36. foreach($arVars[0] as $var)
  37. {
  38. $curVal = str_replace(array('{','}','$'),'',$var);
  39. $newVal = $this->arVars[$curVal];
  40. $content = str_replace($var,$newVal,$content);
  41. }
  42. }
  43.  
  44. function fetchLabels(&$content)
  45. {
  46. $pattern = '/\{config\}.{1,}\{\/config\}/';
  47.  
  48. preg_match($pattern,$content,$arVars);
  49.  
  50. $content = str_replace($arVars,'',$content);
  51.  
  52. foreach($arVars as $var)
  53. {
  54. $curVal = str_replace(array('{config}','{/config}'),'',$var);
  55.  
  56. $path = "lang/{$this->lang}/".$curVal.".cfgte";
  57. $arLabels = parse_ini_file($path);
  58. $pattern = '/\{\#.{1,}\}/';
  59. preg_match_all($pattern,$content,$internalArVars);
  60.  
  61. foreach($internalArVars[0] as $var)
  62. {
  63. $curVal = str_replace(array('{','}','#'),'',$var);
  64. $newVal = $arLabels[$curVal];
  65. $content = str_replace($var,$newVal,$content);
  66. }
  67. }
  68. }
  69. }
  70. ?>

Linha 4 e 5 : Definição das constantes de internacionalização. O valor definido para essas constantes será utilizado como o caminho da pasta
de internacionalização atual
Linha 7 a 10: O construtor recebe o valor do idioma, definido nas linhas 5 e 12 do controlador
Linha 15: Onde tudo começa. Esse método é responsável por compilar o template
Após a linha 15 temos a chamada aos métodos de compilacao de variaveis e labels. Caso eu realmente fosse fazer um template engine, seria ai onde colocaria
novas funcionalidades.
Linha 26: Método assign, ele é que registra uma variável, e armazena o valor dela dentro do array arVars, definido na linha 12.
Linha 31: Método que realiza a compilação (substituição de tags por variáveis). Ele tenta encontrar tags no formato {$}, ou seja, encontra as tags
{$name},{$site} e {$comment} que foram definidas no template e substitui pelos valores registrados dentro do controlador.
Como esse artigo é apenas didático (apesar de não ser uma didática muito boa =) ), utilizei uma maneira de substituir as váriaveis de forma que ficasse tudo ok,
sem me preocupar com desempenho. Utilizei uma combinação de expressão regular com str_replace.
Linha 44: Método responsável pela substiuição dos labels, registrados nos arquivos de internacionalização.
Linha 46: Pesquiso pela tag {config}{/config} para pegar o nome do arquivo de internacionalização que foi definido na linha 1 do template.
Linha 56: Defino o caminho do arquivo de internacionalização no formato lang/idioma/nome do arquivo de internacionalização,que no caso é index.
Por convenção o arquivo de internacionalização deve ter extensão .cfgte .
Linha 59: Parse do arquivo ini.
Linha 61: Dessa linha em diante ocorre a substituição de tags {#} assim como no método de substituição de variaveis, nesse caso serão encontradas
as tags {#name},{#site} e {#comment} que serão substituidas pelos valores registrados dentro dos arquivos de internacionalização.

Dessa forma o TE substitui as variaveis e labels e retorna o conteudo do arquivo de template para o controlador.

O resultado produzido pela execução do controlador será:

Nome: Mathias Grimm

Site: http://mathiasgrimm.com.br

Comentário: Hello World!

Name: Mathias Grimm

Site: http://mathiasgrimm.com.br

Comment: Hello World!

Dessa maneira temos um template engine funcionando...
Um verdadeiro template engine permite muitas outras funcionalidades disponíveis dentro do template. Mas a idéia é essa.
Substituição de código (tags) por valores .
Fica muito mais simples qualquer um dar manutenção no código do template, sem aquele código macarrão php e html.
Dessa forma poderia ser implemento um template engine para outras linguagens também, e utilizar o mesmo template fazendo uma abstração total da camada
de visualização.

Obrigado a todos,voltem sempre!

Para baixar os arquivos utilizados nesse artigo clique AQUI

Write a Comment on Por dentro de um Template Engine

Subscribe

Follow comments by subscribing to the Por dentro de um Template Engine Comments RSS feed.

More

Read more posts by Mathias Grimm

C++ X PHP X PYTHON X PERL X SHELL SCRIPT Criando extensão para php