Templates
O Nette usa o sistema de templates Latte. Por um lado, porque é o sistema de templates mais seguro para PHP e, ao mesmo tempo, o sistema mais intuitivo. Você não precisa aprender muito de novo, basta o conhecimento de PHP e algumas tags.
É comum que uma página seja composta por um template de layout + o template da ação específica. Assim pode parecer um
template de layout, observe os blocos {block}
e a tag {include}
:
<!DOCTYPE html>
<html>
<head>
<title>{block title}Minha App{/block}</title>
</head>
<body>
<header>...</header>
{include content}
<footer>...</footer>
</body>
</html>
E este será o template da ação:
{block title}Página Inicial{/block}
{block content}
<h1>Página Inicial</h1>
...
{/block}
Ele define o bloco content
, que será inserido no lugar de {include content}
no layout, e também
re-define o bloco title
, que sobrescreverá {block title}
no layout. Tente imaginar o resultado.
Procurando templates
Você não precisa especificar nos presenters qual template deve ser renderizado, o framework deduzirá o caminho por si só e economizará sua digitação.
Se você usa uma estrutura de diretórios onde cada presenter tem seu próprio diretório, simplesmente coloque o template
neste diretório com o nome da ação (ou view), ou seja, para a ação default
, use o template
default.latte
:
app/ └── Presentation/ └── Home/ ├── HomePresenter.php └── default.latte
Se você usa uma estrutura onde os presenters estão juntos em um diretório e os templates na pasta templates
,
salve-o no arquivo <Presenter>.<view>.latte
ou <Presenter>/<view>.latte
:
app/ └── Presenters/ ├── HomePresenter.php └── templates/ ├── Home.default.latte ← 1ª variante └── Home/ └── default.latte ← 2ª variante
O diretório templates
também pode estar um nível acima, ou seja, no mesmo nível do diretório com as classes
dos presenters.
Se o template não for encontrado, o presenter responderá com um erro 404 – página não encontrada.
A view é alterada usando $this->setView('outraView')
. Também é possível especificar diretamente o arquivo
de template usando $this->template->setFile('/caminho/para/template.latte')
.
Os arquivos onde os templates são procurados podem ser alterados sobrescrevendo o método formatTemplateFiles(), que retorna um array de possíveis nomes de arquivos.
Procurando o template de layout
O Nette também procura automaticamente o arquivo de layout.
Se você usa uma estrutura de diretórios onde cada presenter tem seu próprio diretório, coloque o layout ou na pasta com o presenter, se for específico apenas para ele, ou um nível acima, se for comum a vários presenters:
app/ └── Presentation/ ├── @layout.latte ← layout comum └── Home/ ├── @layout.latte ← apenas para o presenter Home ├── HomePresenter.php └── default.latte
Se você usa uma estrutura onde os presenters estão juntos em um diretório e os templates na pasta templates
,
o layout será esperado nestes locais:
app/ └── Presenters/ ├── HomePresenter.php └── templates/ ├── @layout.latte ← layout comum ├── Home.@layout.latte ← apenas para Home, 1ª variante └── Home/ └── @layout.latte ← apenas para Home, 2ª variante
Se o presenter estiver em um módulo, a busca também ocorrerá em níveis de diretório superiores, de acordo com o aninhamento do módulo.
O nome do layout pode ser alterado usando $this->setLayout('layoutAdmin')
e então será esperado no arquivo
@layoutAdmin.latte
. Também é possível especificar diretamente o arquivo de template de layout usando
$this->setLayout('/caminho/para/template.latte')
.
Usando $this->setLayout(false)
ou a tag {layout none}
dentro do template, a busca por layout é
desativada.
Os arquivos onde os templates de layout são procurados podem ser alterados sobrescrevendo o método formatLayoutTemplateFiles(), que retorna um array de possíveis nomes de arquivos.
Variáveis no template
Passamos variáveis para o template escrevendo-as em $this->template
e depois as temos disponíveis no
template como variáveis locais:
$this->template->article = $this->articles->getById($id);
Desta forma simples, podemos passar quaisquer variáveis para os templates. No entanto, no desenvolvimento de aplicações robustas, geralmente é mais útil limitar-se. Por exemplo, definindo explicitamente a lista de variáveis que o template espera e seus tipos. Graças a isso, o PHP poderá verificar os tipos, o IDE sugerirá corretamente e a análise estática revelará erros.
E como definimos tal lista? Simplesmente na forma de uma classe e suas propriedades. Nomeamo-la de forma semelhante ao
presenter, apenas com Template
no final:
/**
* @property-read ArticleTemplate $template
*/
class ArticlePresenter extends Nette\Application\UI\Presenter
{
}
class ArticleTemplate extends Nette\Bridges\ApplicationLatte\Template
{
public Model\Article $article;
public Nette\Security\User $user;
// e outras variáveis
}
O objeto $this->template
no presenter será agora uma instância da classe ArticleTemplate
.
Assim, o PHP verificará os tipos declarados ao escrever. E a partir da versão PHP 8.2, também alertará sobre a escrita em uma
variável inexistente; em versões anteriores, o mesmo pode ser alcançado usando a trait Nette\SmartObject.
A anotação @property-read
destina-se ao IDE e à análise estática, graças a ela o autocompletar
funcionará, veja PhpStorm and code completion
for $this->template.

Você pode desfrutar do luxo do autocompletar também nos templates, basta instalar o plugin para Latte no PhpStorm e indicar o nome da classe no início do template, mais no artigo Latte: como usar o sistema de tipos:
{templateType App\Presentation\Article\ArticleTemplate}
...
É assim que os templates em componentes também funcionam, basta seguir a convenção de nomenclatura e para um componente,
por exemplo, FifteenControl
, criar uma classe de template FifteenTemplate
.
Se precisar criar $template
como uma instância de outra classe, use o método createTemplate()
:
public function renderDefault(): void
{
$template = $this->createTemplate(SpecialTemplate::class);
$template->foo = 123;
// ...
$this->sendTemplate($template);
}
Variáveis padrão
Presenters e componentes passam automaticamente várias variáveis úteis para os templates:
$basePath
é o caminho URL absoluto para o diretório raiz (por exemplo,/loja
)$baseUrl
é a URL absoluta para o diretório raiz (por exemplo,http://localhost/loja
)$user
é o objeto representando o usuário$presenter
é o presenter atual$control
é o componente ou presenter atual$flashes
array de mensagens enviadas pela funçãoflashMessage()
Se você usar sua própria classe de template, essas variáveis serão passadas se você criar uma propriedade para elas.
Criação de links
No template, links para outros presenters & ações são criados desta forma:
<a n:href="Product:show">detalhe do produto</a>
O atributo n:href
é muito útil para tags HTML <a>
. Se quisermos exibir o link em outro
lugar, por exemplo, no texto, usamos {link}
:
O endereço é: {link Home:default}
Mais informações podem ser encontradas no capítulo Criando Links URL.
Filtros personalizados, tags, etc.
O sistema de templates Latte pode ser estendido com filtros, funções, tags, etc. personalizados. Isso pode ser feito
diretamente no método render<View>
ou beforeRender()
:
public function beforeRender(): void
{
// adicionando um filtro
$this->template->addFilter('foo', /* ... */);
// ou configuramos diretamente o objeto Latte\Engine
$latte = $this->template->getLatte();
$latte->addFilterLoader(/* ... */);
}
O Latte na versão 3 oferece uma maneira mais avançada, que é criar uma extensão para cada projeto web. Um exemplo fragmentado de tal classe:
namespace App\Presentation\Accessory;
final class LatteExtension extends Latte\Extension
{
public function __construct(
private App\Model\Facade $facade,
private Nette\Security\User $user,
// ...
) {
}
public function getFilters(): array
{
return [
'timeAgoInWords' => $this->filterTimeAgoInWords(...),
'money' => $this->filterMoney(...),
// ...
];
}
public function getFunctions(): array
{
return [
'canEditArticle' =>
fn($article) => $this->facade->canEditArticle($article, $this->user->getId()),
// ...
];
}
// ...
}
Nós a registramos usando a configuração:
latte:
extensions:
- App\Presentation\Accessory\LatteExtension
Tradução
Se você está programando uma aplicação multilíngue, provavelmente precisará exibir alguns textos no template em
diferentes idiomas. O Nette Framework define para este propósito uma interface para tradução Nette\Localization\Translator, que tem um único
método translate()
. Ele recebe a mensagem $message
, que geralmente é uma string, e quaisquer outros
parâmetros. A tarefa é retornar a string traduzida. No Nette, não há implementação padrão, você pode escolher de acordo
com suas necessidades entre várias soluções prontas que podem ser encontradas na Componette. Em sua documentação, você aprenderá como configurar
o tradutor.
É possível definir um tradutor para os templates, que solicitamos, usando o método
setTranslator()
:
protected function beforeRender(): void
{
// ...
$this->template->setTranslator($translator);
}
O tradutor também pode ser definido alternativamente através da configuração:
latte:
extensions:
- Latte\Essential\TranslatorExtension(@Nette\Localization\Translator)
Depois, o tradutor pode ser usado, por exemplo, como um filtro |translate
, incluindo parâmetros adicionais que
são passados para o método translate()
(veja foo, bar
):
<a href="basket">{='Carrinho'|translate}</a>
<span>{$item|translate}</span>
<span>{$item|translate, foo, bar}</span>
Ou como uma tag de sublinhado:
<a href="basket">{_'Carrinho'}</a>
<span>{_$item}</span>
<span>{_$item, foo, bar}</span>
Para traduzir uma seção do template, existe uma tag de par {translate}
(a partir do Latte 2.11, anteriormente
usava-se a tag {_}
):
<a href="order">{translate}Pedido{/translate}</a>
<a href="order">{translate foo, bar}Pedido{/translate}</a>
O tradutor é chamado por padrão em tempo de execução durante a renderização do template. O Latte versão 3, no entanto, pode traduzir todos os textos estáticos já durante a compilação do template. Isso economiza desempenho, pois cada string é traduzida apenas uma vez e a tradução resultante é escrita na forma compilada. No diretório de cache, são criadas várias versões compiladas do template, uma para cada idioma. Para isso, basta apenas especificar o idioma como segundo parâmetro:
protected function beforeRender(): void
{
// ...
$this->template->setTranslator($translator, $lang);
}
Texto estático significa, por exemplo, {_'olá'}
ou {translate}olá{/translate}
. Textos não
estáticos, como {_$foo}
, continuarão a ser traduzidos em tempo de execução.