Plugins Smarty para Geração de HTML


1Introdução

Ao criar templates Smarty, você pode usar estruturas de controle (condições {if}, laços {foreach}, etc.), tags personalizadas ({cycle}, {mailto}, {math}, etc.) e modificadores (default, date_format, escape, replace, etc.) fornecidos pelo Smarty.

Para facilitar o desenvolvimento, você pode criar suas próprias tags e modificadores personalizados. Veja um exemplo de cada um.


2Criar um modificador personalizado

Vamos criar um modificador que traduz uma string para outro idioma.
(veja a documentação do Smarty sobre a criação de modificadores)

Por exemplo, escrevendo isto em um template Smarty:

{* tradução direta de uma string *}
{"Título do artigo"|translate:'en'}

{* tradução do conteúdo de uma variável *}
{$product1.type|translate:'en'}
{$product2.type|translate:'en'}

Você poderia obter o seguinte resultado:

Article title

Computer
Screen

Para desenvolver esse modificador, vamos usar a fonte de dados que se conecta à API do Deepl, que vimos no tutorial anterior. O código do modificador pressupõe a presença dessa fonte de dados no arquivo de configuração, sob o nome transl.
Aqui está o código do modificador, a ser salvo no arquivo lib/smarty-plugins/modifier.translate.php:

<?php

/**
 * Modificador Smarty para tradução de textos.
 * @param   string    $text    String a ser traduzida.
 * @param   string    $lang    Idioma para o qual o texto será traduzido.
 * @return  string    O texto traduzido.
 */
function smarty_modifier_translate(string $text, string $lang) : string {
    // recuperação da fonte de dados
    global $temma;
    $datasource = $temma->getLoader()->dataSources->transl ?? null;
    if (!$datasource)
        return ($text);

    // chama a API do Deepl para traduzir a string
    try {
        $result = $datasource->translate($text, $lang);
    } catch (\Exception $e) {
        $result = null;
    }

    return ($result ?: $text);
}
  • Linha 9: definição da função smarty_modifier_translate().
  • Linha 11: definição da variável global $temma, que contém o objeto principal do framework.
  • Linha 12: uso da variável global para recuperar o componente de injeção de dependências (com o método getLoader()), depois recuperar o array de fontes de dados, e a partir dele recuperar a fonte de dados conectada à API do Deepl.
  • Linhas 13 e 14: se a fonte de dados não estiver definida, o texto original (não traduzido) é retornado.
  • Linhas 17 a 21: chamada à fonte de dados para traduzir o texto.
  • Linha 23: retorna o texto traduzido. Se estiver vazio, o texto original é retornado.

3Criar uma tag personalizada

Vamos imaginar que você queira criar uma tag Smarty para facilitar a criação de títulos.
(veja a documentação do Smarty sobre a criação de tags personalizadas).

Por exemplo, escrevendo isto no seu template:

{title text="Primeiro título" level="1"}
{title text="Primeiro subtítulo" level="2"}
<p>Bla bla</p>

{title text="Segundo subtítulo" level="2"}
<p>Bla bla</p>

{title text="Segundo título" level="1"}
{title text="Primeiro subtítulo" level="2"}
<p>Bla bla</p>

{title text="Segundo subtítulo" level="2"}
<p>Bla bla</p>

Você obteria o seguinte código HTML:

<h1 id="1-primeiro-titulo">1 Primeiro título</h1>
<h2 id="1-1-primeiro-subtitulo">1.1 Primeiro subtítulo</h2>
<p>Bla bla</p>

<h2 id="1-2-segundo-subtitulo">1.2 Segundo subtítulo</h2>
<p>Bla bla</p>

<h1 id="2-segundo-titulo">2 Segundo título</h1>
<h2 id="2-1-primeiro-subtitulo">2.1 Primeiro subtítulo</h2>
<p>Bla bla</p>

<h2 id="2-2-segundo-subtitulo">2.2 Segundo subtítulo</h2>
<p>Bla bla</p>

Aqui está o código de uma tag personalizada assim, a ser salvo no arquivo lib/smarty-plugins/function.title.php:

<?php

/**
 * Tag Smarty usada para inserir títulos HTML.
 * @param   array             $params   Array associativo contendo os parâmetros fornecidos à tag.
 * @param   \Smarty\Template  $template Objeto que representa o template processado.
 * @return  string   O código HTML gerado.
 */
function smarty_tag_title($params, $template) {
    // inicializa a variável estática $levelsCount,
    // que contém a profundidade de cada nível de título
    static $levelsCount = [0];

    // recuperação dos parâmetros
    $text = trim($params['text'] ?? null);
    $level = intval($params['level'] ?? 1) ?: 1;

    // verificação
    if (!$text)
        return ('');

    // gerenciamento da variável estática
    $levelsCount = array_slice($levelsCount, 0, $level);
    $levelsCount[$level - 1] ??= 0;
    $levelsCount[$level - 1]++;

    // preparação do resultado
    $title = implode('.', $levelsCount) . ' ' . $text;
    $id = \Temma\Utils\Text::urlize($title);

    return sprintf('<h%d id="%s">%s</h%d>', $level, $id, $title, $level);
}
  • Linha 9: declaração da função smarty_tag_title(). Ela recebe dois parâmetros, um array associativo contendo os parâmetros definidos no template, e um objeto que representa o template no qual a tag foi usada (não vamos usar esse objeto).
  • Linha 12: definição de uma variável estática inicializada com um array contendo um número inteiro igual a zero. O fato de ser uma variável estática significa que ela manterá seu valor entre cada chamada da função. Essa variável contém a profundidade de cada nível de título, ou seja, o número de títulos conhecidos para cada nível de título atual.
  • Linhas 15 e 16: recupera os parâmetros fornecidos à tag no template. Valores ausentes ou incorretos são tratados.
  • Linhas 19 e 20: tratamento de texto vazio.
  • Linha 23: o array $levelsCount é reduzido se necessário, quando o nível de título passado como parâmetro é menor que o anterior.
  • Linhas 24 e 25: no array $levelsCount, a entrada correspondente ao nível de título passado como parâmetro é incrementada (depois de ser inicializada em zero, se necessário).
  • Linhas 28 e 29: definição do título a ser inserido no código HTML, e do identificador associado. Para gerar o identificador, aplica-se a função urlize() ao título.
  • Linha 31: retorna a string HTML formada pela tag <Hn>, com o identificador como atributo e o título como conteúdo.

4Criar uma tag de bloco personalizada

Tags de bloco são estruturas de controle que têm um elemento de abertura ({tag_name}) e um elemento de fechamento ({/tag_name}), e que podem atuar sobre o conteúdo colocado entre esses dois elementos.
(veja a documentação do Smarty sobre a criação de tags de bloco personalizadas)

Para ilustrar como isso funciona, vamos escrever uma tag de bloco equivalente à tag {title} vista acima. Você verá as diferenças, tanto no código Smarty quanto na implementação PHP.

Por exemplo, se você escrever o seguinte no seu template:

{title level="1"}Primeiro título{/title}
{title level="2"}Primeiro subtítulo{/title}
<p>Bla bla</p>

{title level="2"}Segundo subtítulo{/title}
<p>Bla bla</p>

{title level="1"}Segundo título{/title}
{title level="2"}Primeiro subtítulo{/title}
<p>Bla bla</p>

{title level="2"}Segundo subtítulo{/title}
<p>Bla bla</p>

Você obteria o seguinte código HTML:

<h1 id="1-primeiro-titulo">1 Primeiro título</h1>
<h2 id="1-1-primeiro-subtitulo">1.1 Primeiro subtítulo</h2>
<p>Bla bla</p>

<h2 id="1-2-segundo-subtitulo">1.2 Segundo subtítulo</h2>
<p>Bla bla</p>

<h1 id="2-segundo-titulo">2 Segundo título</h1>
<h2 id="2-1-primeiro-subtitulo">2.1 Primeiro subtítulo</h2>
<p>Bla bla</p>

<h2 id="2-2-segundo-subtitulo">2.2 Segundo subtítulo</h2>
<p>Bla bla</p>

Aqui está o código de uma tag de bloco personalizada assim, a ser salvo no arquivo lib/smarty-plugins/block.title.php:

<?php

/**
 * Tag de bloco Smarty usada para inserir títulos HTML.
 * @param   array             $params   Array associativo contendo os parâmetros fornecidos à tag.
 * @param   string            $content  Conteúdo colocado entre as tags de abertura e fechamento.
 * @param   \Smarty\Template  $template Objeto que representa o template processado.
 * @param   bool              $repeat   Falso para a tag de fechamento.
 * @return  ?string    O código HTML gerado.
 */
function smarty_block_title($params, $content, $template, &$repeat) {
    if ($repeat)
        return (null);

    // inicializa a variável estática $levelsCount,
    // que contém a profundidade de cada nível de título
    static $levelsCount = [0];

    // recuperação dos parâmetros
    $content = trim($content ?? '');
    $level = intval($params['level'] ?? 1) ?: 1;

    // verificação
    if (!$content)
        return ('');

    // gerenciamento da variável estática
    $levelsCount = array_slice($levelsCount, 0, $level);
    $levelsCount[$level - 1] ??= 0;
    $levelsCount[$level - 1]++;

    // preparação do resultado
    $title = implode('.', $levelsCount) . ' ' . $content;
    $id = \Temma\Utils\Text::urlize($title);

    return sprintf('<h%d id="%s">%s</h%d>', $level, $id, $title, $level);
}
  • Linha 11: declaração da função smarty_block_title(). Ela recebe quatro parâmetros: um array associativo contendo os parâmetros definidos no template, o texto contido entre as tags de abertura e fechamento, um objeto que representa o template no qual a tag foi usada (não vamos usar esse objeto), e um booleano indicando se a função é chamada na leitura da tag de abertura ou de fechamento.
  • Linhas 12 e 13: se a chamada da função for para a tag de abertura, null é retornado, pois o texto contido entre as tags de abertura e fechamento ainda não está disponível. Todo o processamento ocorrerá quando a função for chamada para a tag de fechamento.
  • Linha 17: definição de uma variável estática inicializada com um array contendo um número inteiro igual a zero. O fato de ser uma variável estática significa que ela manterá seu valor entre cada chamada da função. Essa variável contém a profundidade de cada nível de título, ou seja, o número de títulos conhecidos para cada nível de título atual.
  • Linhas 20 e 21: recupera os parâmetros fornecidos à tag no template. Valores ausentes ou incorretos são tratados.
  • Linhas 24 e 25: tratamento de texto vazio.
  • Linha 28: o array $levelsCount é reduzido se necessário, quando o nível de título passado como parâmetro é menor que o anterior.
  • Linhas 29 e 30: no array $levelsCount, a entrada correspondente ao nível de título passado como parâmetro é incrementada (depois de ser inicializada em zero, se necessário).
  • Linhas 33 e 34: definição do título a ser inserido no código HTML, e do identificador associado. Para gerar o identificador, aplica-se a função urlize() ao título.
  • Linha 36: retorna a string HTML formada pela tag <Hn>, com o identificador como atributo e o título como conteúdo.