Estendendo o Latte
O Latte foi projetado com a extensibilidade em mente. Embora seu conjunto padrão de tags, filtros e funções cubra muitos casos de uso, muitas vezes você precisa adicionar sua própria lógica específica ou ferramentas auxiliares. Esta página fornece uma visão geral das maneiras de estender o Latte para que ele corresponda perfeitamente aos requisitos do seu projeto – desde ajudantes simples até novas sintaxes complexas.
Formas de estender o Latte
Aqui está uma visão geral rápida das principais maneiras de personalizar e estender o Latte:
- Filtros personalizados: Para formatar ou transformar dados
diretamente na saída do template (por exemplo,
{$var|myFilter}
). Ideal para tarefas como formatação de datas, modificações de texto ou aplicação de escaping específico. Você também pode usá-los para modificar blocos maiores de conteúdo HTML, envolvendo o conteúdo em um{block}
anônimo e aplicando um filtro personalizado a ele. - Funções personalizadas: Para adicionar lógica
reutilizável que pode ser chamada dentro de expressões no template (por exemplo,
{myFunction($arg1, $arg2)}
). Útil para cálculos, acesso a funções auxiliares do aplicativo ou geração de pequenas partes de conteúdo. - Tags personalizadas: Para criar construções de linguagem
totalmente novas (
{mytag}...{/mytag}
oun:mytag
). As tags oferecem mais possibilidades, permitem definir estruturas personalizadas, controlar a análise do template e implementar lógica de renderização complexa. - Passes de compilação: Funções que modificam a árvore de sintaxe abstrata (AST) do template após a análise, mas antes da geração do código PHP. Usadas para otimizações avançadas, verificações de segurança (como Sandbox) ou modificações automáticas de código.
- Loaders personalizados: Para alterar a forma como o Latte localiza e carrega arquivos de template (por exemplo, carregar do banco de dados, armazenamento criptografado, etc.).
Escolher o método de extensão correto é crucial. Antes de criar uma tag complexa, considere se um filtro ou função mais simples seria suficiente. Vamos ilustrar com um exemplo: implementação de um gerador Lorem ipsum que recebe o número de palavras a serem geradas como argumento.
- Como tag?
{lipsum 40}
– Possível, mas as tags são mais adequadas para estruturas de controle ou geração de marcação complexa. As tags não podem ser usadas diretamente em expressões. - Como filtro?
{=40|lipsum}
– Tecnicamente funciona, mas os filtros são destinados a transformar o valor de entrada. Aqui,40
é um argumento, não um valor que está sendo transformado. Isso parece semanticamente incorreto. - Como função?
{lipsum(40)}
– Esta é a solução mais natural! As funções aceitam argumentos e retornam valores, o que é ideal para uso em qualquer expressão:{var $text = lipsum(40)}
.
Recomendação geral: Use funções para cálculos/geração, filtros para transformação e tags para novas construções de linguagem ou marcação complexa. Use passes para manipulação de AST e loaders para obter templates.
Registro direto
Para ferramentas auxiliares específicas do projeto ou extensões rápidas, o Latte permite o registro direto de filtros e
funções no objeto Latte\Engine
.
Para registrar um filtro, use o método addFilter()
. O primeiro argumento da sua função de filtro será
o valor antes do caractere |
e os argumentos seguintes são aqueles passados após os dois pontos
:
.
$latte = new Latte\Engine;
// Definição do filtro (objeto chamável: função, método estático, etc.)
$myTruncate = fn(string $s, int $length = 50) => mb_substr($s, 0, $length);
// Registro
$latte->addFilter('truncate', $myTruncate);
// Uso no template: {$text|truncate} ou {$text|truncate:100}
Você também pode registrar um Filter Loader, uma função que fornece dinamicamente objetos chamáveis de filtros com base no nome solicitado:
$latte->addFilterLoader(fn(string $name) => /* retorna um objeto chamável ou null */);
Para registrar uma função utilizável em expressões de template, use addFunction()
.
$latte = new Latte\Engine;
// Definição da função
$isWeekend = fn(DateTimeInterface $date) => $date->format('N') >= 6;
// Registro
$latte->addFunction('isWeekend', $isWeekend);
// Uso no template: {if isWeekend($myDate)}Fim de semana!{/if}
Mais informações podem ser encontradas nas seções Criando filtros personalizados e Funções.
Método robusto: Extensão Latte
Embora o registro direto seja simples, a maneira padrão e recomendada de empacotar e distribuir extensões Latte é através de classes Extension. A Extension serve como um ponto de configuração central para registrar múltiplas tags, filtros, funções, passes de compilação e outros elementos.
Por que usar Extensions?
- Organização: Mantém extensões relacionadas (tags, filtros, etc. para uma funcionalidade específica) juntas em uma única classe.
- Reutilização e compartilhamento: Empacote facilmente suas extensões para uso em outros projetos ou para compartilhar com a comunidade (por exemplo, via Composer).
- Poder total: Tags personalizadas e passes de compilação só podem ser registrados através de Extensions.
Registrando uma Extensão
Uma Extension é registrada no Latte usando o método addExtension()
(ou através do arquivo de configuração):
$latte = new Latte\Engine;
$latte->addExtension(new MyProjectExtension);
Se você registrar várias extensões e elas definirem tags, filtros ou funções com o mesmo nome, a extensão adicionada por último tem precedência. Isso também significa que suas extensões podem sobrescrever tags/filtros/funções nativas.
Sempre que você fizer uma alteração na classe e a atualização automática não estiver desativada, o Latte recompilará automaticamente seus templates.
Criando uma Extensão
Para criar sua própria extensão, você precisa criar uma classe que herde de Latte\Extension. Para ter uma ideia de como essa extensão se parece, dê uma olhada na CoreExtension embutida.
Vamos dar uma olhada nos métodos que você pode implementar:
beforeCompile (Latte\Engine $engine): void
Chamado antes da compilação do template. O método pode ser usado, por exemplo, para inicializações relacionadas à compilação.
getTags(): array
Chamado durante a compilação do template. Retorna um array associativo nome da tag ⇒ objeto chamável, que são funções para analisar tags. Mais informações.
public function getTags(): array
{
return [
'foo' => FooNode::create(...),
'bar' => BarNode::create(...),
'n:baz' => NBazNode::create(...),
// ...
];
}
A tag n:baz
representa um n:atributo puro, ou
seja, uma tag que só pode ser escrita como um atributo.
Para as tags foo
e bar
, o Latte reconhece automaticamente se são tags pares e, se sim, podem ser
escritas automaticamente usando n:atributos, incluindo variantes com os prefixos n:inner-foo
e
n:tag-foo
.
A ordem de execução desses n:atributos é determinada pela sua ordem no array retornado pelo método getTags()
.
Assim, n:foo
é sempre executado antes de n:bar
, mesmo que os atributos na tag HTML estejam listados na
ordem inversa, como <div n:bar="..." n:foo="...">
.
Se você precisar especificar a ordem dos n:atributos entre várias extensões, use o método auxiliar order()
,
onde o parâmetro before
ou after
especifica quais tags são ordenadas antes ou depois da tag.
public function getTags(): array
{
return [
'foo' => self::order(FooNode::create(...), before: 'bar'),
'bar' => self::order(BarNode::create(...), after: ['block', 'snippet']),
];
}
getPasses(): array
Chamado durante a compilação do template. Retorna um array associativo nome do passe ⇒ objeto chamável, que são funções representando os chamados passes de compilação, que percorrem e modificam a AST.
Aqui também pode ser usado o método auxiliar order()
. O valor dos parâmetros before
ou
after
pode ser *
com o significado de antes/depois de todos.
public function getPasses(): array
{
return [
'optimize' => Passes::optimizePass(...),
'sandbox' => self::order($this->sandboxPass(...), before: '*'),
// ...
];
}
beforeRender (Latte\Engine $engine): void
Chamado antes de cada renderização do template. O método pode ser usado, por exemplo, para inicializar variáveis usadas durante a renderização.
getFilters(): array
Chamado antes da renderização do template. Retorna filtros como um array associativo nome do filtro ⇒ objeto chamável. Mais informações.
public function getFilters(): array
{
return [
'batch' => $this->batchFilter(...),
'trim' => $this->trimFilter(...),
// ...
];
}
getFunctions(): array
Chamado antes da renderização do template. Retorna funções como um array associativo nome da função ⇒ objeto chamável. Mais informações.
public function getFunctions(): array
{
return [
'clamp' => $this->clampFunction(...),
'divisibleBy' => $this->divisibleByFunction(...),
// ...
];
}
getProviders(): array
Chamado antes da renderização do template. Retorna um array de provedores, que geralmente são objetos usados por tags em
tempo de execução. Eles são acessados via $this->global->...
. Mais informações.
public function getProviders(): array
{
return [
'myFoo' => $this->foo,
'myBar' => $this->bar,
// ...
];
}
getCacheKey (Latte\Engine $engine): mixed
Chamado antes da renderização do template. O valor de retorno se torna parte da chave, cujo hash está contido no nome do arquivo do template compilado. Portanto, para diferentes valores de retorno, o Latte gerará diferentes arquivos de cache.