Carregadores de modelos
Os carregadores são o mecanismo que o Latte utiliza para recuperar o código-fonte de seus modelos. Geralmente, os modelos são arquivos armazenados em disco, mas o sistema flexível de carregadores do Latte permite carregá-los de praticamente qualquer lugar ou até mesmo gerá-los dinamicamente.
O que é um Loader?
Normalmente, quando você trabalha com modelos, pensa em arquivos .latte
que residem na estrutura de diretórios
do seu projeto. Isso é tratado pelo FileLoader padrão do Latte. Entretanto, a conexão entre
o nome de um modelo (como 'main.latte'
ou 'components/card.latte'
) e o conteúdo real do código-fonte
não precisa ser um mapeamento direto do caminho do arquivo.
É aí que entram os loaders. Um loader é um objeto responsável por pegar um nome de modelo (uma string de identificador) e
fornecer ao Latte seu código-fonte. O Latte depende inteiramente do carregador configurado para essa tarefa. Isso se aplica não
apenas ao modelo inicial solicitado via $latte->render('main.latte')
, mas também a todos os modelos
referenciados dentro usando tags como {include ...}
, {layout ...}
, {embed ...}
, ou
{import ...}
.
Por que usar um carregador personalizado?
- Carregamento de fontes alternativas:** Buscar modelos armazenados em um banco de dados, um cache (como Redis ou Memcached), um sistema de controle de versão (como Git, com base em um commit específico) ou gerados dinamicamente.
- Implementação de convenções de nomenclatura personalizadas:** Talvez você queira usar aliases mais curtos para os modelos ou implementar uma lógica de caminho de pesquisa específica (por exemplo, procurar primeiro em um diretório de temas e, em seguida, retornar a um diretório padrão).
- Adição de segurança ou controle de acesso:** Um carregador personalizado pode verificar as permissões do usuário antes de carregar determinados modelos.
- Pré-processamento:** Embora geralmente não seja recomendado( é melhor usarpassagens do compilador ), um carregador poderia teoricamente pré-processar o conteúdo do modelo antes de entregá-lo ao Latte.
Você configura o carregador para sua instância Latte\Engine
usando o método setLoader()
:
$latte = new Latte\Engine;
// Usar o FileLoader padrão para arquivos em '/path/to/templates'
$loader = new Latte\Loaders\FileLoader('/path/to/templates');
$latte->setLoader($loader);
Um carregador deve implementar a interface Latte\Loader
.
Carregadores incorporados
O Latte oferece vários carregadores padrão:
FileLoader
Esse é o carregador padrão usado pelo Latte\Engine
se nenhum outro carregador for especificado. Ele
carrega modelos diretamente do sistema de arquivos.
Opcionalmente, você pode definir um diretório raiz para restringir o acesso:
use Latte\Loaders\FileLoader;
// O seguinte só permitirá o carregamento de modelos em /var/www/html/templates
$loader = new FileLoader('/var/www/html/templates');
$latte->setLoader($loader);
// $latte->render('../../../etc/passwd'); // Isso lançaria uma exceção
// Renderizar o modelo localizado em /var/www/html/templates/pages/contact.latte
$latte->render('pages/contact.latte');
Ele resolve nomes de modelos relativos ao modelo atual ao usar tags como {include}
ou {layout}
, a
menos que seja fornecido um caminho absoluto.
Carregador de strings
Esse carregador recupera o conteúdo do modelo de uma matriz associativa em que as chaves são nomes de modelos (identificadores) e os valores são as cadeias de código-fonte do modelo. É particularmente útil para testes ou pequenos aplicativos em que os modelos podem ser armazenados no próprio código PHP.
use Latte\Loaders\StringLoader;
$loader = new StringLoader([
'main.latte' => 'Hello {$name}, include is below:{include helper.latte}',
'helper.latte' => '{var $x = 10}Included content: {$x}',
// Adicione mais modelos conforme necessário
]);
$latte->setLoader($loader);
$latte->render('main.latte', ['name' => 'World']);
// Saídas: Hello World, o include está abaixo:Conteúdo incluído: 10
Se você só precisa renderizar um único modelo diretamente de uma string sem precisar de includes ou herança referenciando
outros modelos de string nomeados, pode passar a string diretamente para render()
ou renderToString()
ao
usar StringLoader
sem um array:
$loader = new StringLoader;
$latte->setLoader($loader);
$templateString = 'Hello {$name}!';
$output = $latte->renderToString($templateString, ['name' => 'Alice']);
// $output contém "Hello Alice!".
Criação de um carregador personalizado
Para criar seu próprio carregador (por exemplo, para carregar modelos de um banco de dados, cache, controle de versão ou outra fonte), é necessário criar uma classe que implemente a interface Latte\Loader.
Vamos dar uma olhada no que cada método precisa fazer.
getContent (string $name): string
Esse é o método principal do carregador. Sua responsabilidade é recuperar e retornar o conteúdo completo do código-fonte
do modelo identificado por $name
(conforme passado para $latte->render()
ou retornado por getReferredName()).
Se o modelo não puder ser encontrado ou acessado, esse método deve lançar um
Latte\RuntimeException
.
public function getContent(string $name): string
{
// Exemplo: Buscar em um armazenamento interno hipotético
$content = $this->storage->read($name);
if ($content === null) {
throw new Latte\RuntimeException("Template '$name' cannot be loaded.");
}
return $content;
}
getReferredName (string $name, string $referringName): string
Esse método lida com a resolução de nomes de modelos usados em tags como {include}
, {layout}
, etc.
Quando o Latte encontra, por exemplo, {include 'partial.latte'}
dentro de main.latte
, ele chama esse
método com $name = 'partial.latte'
e $referringName = 'main.latte'
.
O trabalho do método é resolver $name
em um identificador canônico (por exemplo, um caminho absoluto, uma
chave de banco de dados exclusiva), que será usado ao chamar outros métodos do carregador, com base no contexto fornecido por
$referringName
.
public function getReferredName(string $name, string $referringName): string
{
return ...;
}
getUniqueId (string $name): string
O Latte usa o cache de modelos compilados para melhorar o desempenho. Cada arquivo de modelo compilado precisa de um nome
exclusivo derivado do identificador do modelo de origem. Esse método fornece uma string que identifica exclusivamente
o modelo $name
.
Para modelos baseados em arquivos, o caminho absoluto pode funcionar. Para modelos de banco de dados, é comum a combinação de um prefixo e o ID do banco de dados.
public function getUniqueId(string $name): string
{
return ...;
}
Exemplo: Carregador de banco de dados simples
Este exemplo demonstra a estrutura básica de um carregador que recupera modelos armazenados em uma tabela de banco de dados
chamada templates
com as colunas name
(identificador exclusivo), content
e
updated_at
.
use Latte;
class DatabaseLoader implements Latte\Loader
{
public function __construct(
private \PDO $db,
) {
}
public function getContent(string $name): string
{
$stmt = $this->db->prepare('SELECT content FROM templates WHERE name = ?');
$stmt->execute([$name]);
$content = $stmt->fetchColumn();
if ($content === false) {
throw new Latte\RuntimeException("Template '$name' not found in database.");
}
return $content;
}
// Este exemplo simples pressupõe que os nomes dos modelos ("homepage", "article" etc.)
// são IDs exclusivos e os modelos não fazem referência uns aos outros de forma relativa.
public function getReferredName(string $name, string $referringName): string
{
return $name;
}
public function getUniqueId(string $name): string
{
// Usar um prefixo e o próprio nome é único e suficiente aqui
return 'db_' . $name;
}
}
// Uso:
$pdo = new \PDO(/* connection details */);
$loader = new DatabaseLoader($pdo);
$latte->setLoader($loader);
$latte->render('homepage'); // Carrega o modelo com o nome "homepage" do banco de dados
Os carregadores personalizados oferecem controle total sobre a origem dos modelos do Latte, permitindo a integração com vários sistemas de armazenamento e fluxos de trabalho.