Práticas para os desenvolvedores

Instalação

A melhor maneira de instalar o Latte é usar um Composer:

composer require latte/latte

Versões PHP suportadas (aplica-se às últimas versões de correção Latte):

versão compatível com PHP
Latte 3.0 PHP 8.0 – 8.2
Latte 2.11 PHP 7.1 – 8.2
Latte 2.8 – 2.10 PHP 7.1 – 8.1

Como fazer um modelo

Como fazer um modelo? Basta usar este código simples:

$latte = new Latte\Engine;
// diretório de cache
$latte->setTempDirectory('/path/to/tempdir');

$params = [ /* template variables */ ];
// ou $params = novos parâmetros TemplateParameters(/* ... */);

// render à saída
$latte->render('template.latte', $params);
// ou render a variável
$output = $latte->renderToString('template.latte', $params);

Os parâmetros podem ser arrays ou até melhor objeto, o que proporcionará verificação de tipo e sugestão no editor.

Você também pode encontrar exemplos de uso no repositório de exemplos Latte.

Desempenho e Caching

Os modelos Latte são extremamente rápidos, porque o Latte os compila diretamente em código PHP e os armazena em cache em disco. Assim, eles não têm despesas extras em comparação com os modelos escritos em PHP puro.

O cache é automaticamente regenerado cada vez que você muda o arquivo fonte. Assim, você pode editar convenientemente seus modelos Latte durante o desenvolvimento e ver as mudanças imediatamente no navegador. Você pode desativar este recurso em um ambiente de produção e economizar um pouco de desempenho:

$latte->setAutoRefresh(false);

Quando implantada em um servidor de produção, a geração inicial de cache, especialmente para aplicações maiores, pode, compreensivelmente, demorar um pouco. O Latte tem prevenção embutida contra a “debandada do cache:https://en.wikipedia.org/…che_stampede”. Esta é uma situação em que o servidor recebe um grande número de solicitações simultâneas e como o cache do Latte ainda não existe, todos eles o gerariam ao mesmo tempo. O que aumenta a CPU. O Latte é inteligente, e quando há várias solicitações simultâneas, apenas o primeiro tópico gera o cache, os outros esperam e depois o utilizam.

Parâmetros como classe

Melhor do que passar variáveis para o modelo como matrizes é criar uma classe. Você recebe notação de segurança de tipo, boa sugestão no IDE e uma forma de registrar filtros e funções.

class MailTemplateParameters
{
	public function __construct(
		public string $lang,
		public Address $address,
		public string $subject,
		public array $items,
		public ?float $price = null,
	) {}
}

$latte->render('mail.latte', new MailTemplateParameters(
	lang: $this->lang,
	subject: $title,
	price: $this->getPrice(),
	items: [],
	address: $userAddress,
));

Desativação do Auto-Escaping da variável

Se a variável contém uma string HTML, você pode marcá-la para que Latte não fuja automaticamente (e portanto duplique) dela. Isto evita a necessidade de especificar |noescape no modelo.

A maneira mais fácil é enrolar o cordel em um objeto Latte\Runtime\Html:

$params = [
	'articleBody' => new Latte\Runtime\Html($article->htmlBody),
];

O Latte também não escapa de todos os objetos que implementam a interface Latte\HtmlStringable. Assim, você pode criar sua própria classe cujo método __toString() retornará o código HTML que não escapará automaticamente:

class Emphasis extends Latte\HtmlStringable
{
	public function __construct(
		private string $str,
	) {
	}

	public function __toString(): string
	{
		return '<em>' . htmlspecialchars($this->str) . '</em>';
	}
}

$params = [
	'foo' => new Emphasis('hello'),
];

O método __toString deve retornar o HTML correto e fornecer parâmetros que escapem, caso contrário pode ocorrer uma vulnerabilidade XSS!

Como estender o Latte com filtros, etiquetas, etc.

Como adicionar um filtro personalizado, função, etiqueta, etc. ao Latte? Descubra no capítulo que estende o Latte. Se você quiser reutilizar suas alterações em diferentes projetos ou se quiser compartilhá-las com outros, você deve então criar uma extensão.

Qualquer código no modelo {php ...}

Somente expressões PHP podem ser escritas dentro do {do} por isso não é possível, por exemplo, inserir construções como if ... else ou declarações em ponto-e-vírgula.

Entretanto, você pode registrar a extensão RawPhpExtension, que acrescenta a tag {php ...}, que pode ser usada para inserir qualquer código PHP por conta e risco do autor do modelo.

$latte->addExtension(new Latte\Essential\RawPhpExtension);

Tradução em Modelos

Use a extensão TranslatorExtension para adicionar {_...}, {translate} e filtro translate para o modelo. Eles são usados para traduzir valores ou partes do modelo para outros idiomas. O parâmetro é o método (chamado PHP) que realiza a tradução:

class MyTranslator
{
	public function __construct(private string $lang)
	{}

	public function translate(string $original): string
	{
		// criar $translated from $original according to $this->lang
		return $translated;
	}
}

$translator = new MyTranslator($lang);
$extension = new Latte\Essential\TranslatorExtension(
	$translator->translate(...), // [$translator, 'translate'] in PHP 8.0
);
$latte->addExtension($extension);

O tradutor é chamado no momento da execução, quando o modelo é renderizado. Entretanto, o Latte pode traduzir todos os textos estáticos durante a compilação do modelo. Isto economiza desempenho porque cada string é traduzida apenas uma vez e a tradução resultante é escrita no arquivo compilado. Isto cria múltiplas versões compiladas do modelo no diretório do cache, uma para cada idioma. Para fazer isto, basta especificar o idioma como segundo parâmetro:

$extension = new Latte\Essential\TranslatorExtension(
	$translator->translate(...),
	$lang,
);

Por texto estático entendemos, por exemplo, {_'hello'} ou {translate}hello{/translate}. Textos não estáticos, como {_$foo}, continuarão a ser traduzidos em tempo de execução.

O modelo também pode passar parâmetros adicionais para o tradutor via {_$original, foo: bar} ou {translate foo: bar}, que recebe como a matriz $params:

public function translate(string $original, ...$params): string
{
	// $params['foo'] === 'bar'
}

Depuração e Tracy

Latte tenta tornar o desenvolvimento tão agradável quanto possível. Para fins de depuração, existem três tags {dump}, {debugbreak} e {trace}.

Você terá o maior conforto se instalar a grande ferramenta de depuração Tracy e ativar o plugin Latte:

// permite que Tracy
Tracy\Debugger::enable();

$latte = new Latte\Engine;
// ativa a extensão da Tracy
$latte->addExtension(new Latte\Bridges\Tracy\TracyExtension);

Agora você verá todos os erros em uma bela tela vermelha, incluindo erros em modelos com destaque de linha e coluna (vídeo). Ao mesmo tempo, no canto inferior direito da chamada Barra Tracy, aparece uma aba para Latte, onde você pode ver claramente todos os modelos renderizados e suas relações (incluindo a possibilidade de clicar no modelo ou código compilado), bem como as variáveis:

Como o Latte compila os modelos em código PHP legível, você pode passar convenientemente por eles em seu IDE.

Linter: Validação da sintaxe do gabarito

A ferramenta Linter o ajudará a percorrer todos os modelos e verificar a existência de erros de sintaxe. Ela é lançada a partir do console:

vendor/bin/latte-lint <path>

Se você usa etiquetas personalizadas, crie também seu Linter personalizado, por exemplo, custom-latte-lint:

#!/usr/bin/env php
<?php

// digite o caminho real para o arquivo autoload.php
require __DIR__ . '/vendor/autoload.php';

$linter = new Latte\Tools\Linter($engine);
$linter->scanDirectory($path);

$engine = new Latte\Engine;
// registra aqui extensões individuais
$engine->addExtension(/* ... */);

$path = $argv[1];
$linter = new Latte\Tools\Linter(engine: $engine);
$ok = $linter->scanDirectory($path);
exit($ok ? 0 : 1);

Carregando modelos a partir de uma corda

Necessidade de carregar modelos de cordas em vez de arquivos, talvez para fins de teste? O StringLoader o ajudará:

$latte->setLoader(new Latte\Loaders\StringLoader([
	'main.file' => '{include other.file}',
	'other.file' => '{if true} {$var} {/if}',
]));

$latte->render('main.file', $params);

Manipulador de Exceções

Você pode definir seu próprio manipulador para as exceções esperadas. Exceções levantadas no interior {try} e na caixa de areia são passados para ela.

$loggingHandler = function (Throwable $e, Latte\Runtime\Template $template) use ($logger) {
	$logger->log($e);
};

$latte = new Latte\Engine;
$latte->setExceptionHandler($loggingHandler);

Procura automática de layout

Usando a etiqueta {layout} o modelo determina seu modelo pai. Também é possível ter o layout pesquisado automaticamente, o que simplificará a escrita dos modelos, uma vez que eles não precisarão incluir a tag {layout}.

Isto é conseguido da seguinte forma:

$finder = function (Latte\Runtime\Template $template) {
	if (!$template->getReferenceType()) {
		// ele retorna o caminho para o arquivo de modelo pai
		return 'automatic.layout.latte';
	}
};

$latte = new Latte\Engine;
$latte->addProvider('coreParentFinder', $finder);

Se o modelo não deve ter um layout, ele o indicará com a tag {layout none}.