Szablony
Nette wykorzystuje system szablonów Latte. Po pierwsze dlatego, że jest to najbezpieczniejszy system szablonowania dla PHP, a także najbardziej intuicyjny. Nie musisz uczyć się wielu nowych rzeczy, wystarczy znajomość PHP i kilka tagów.
Często zdarza się, że strona składa się z szablonu układu + szablonu akcji. Na przykład tak może wyglądać szablon
układu, zauważ bloki {block}
i znacznik {include}
:
<!DOCTYPE html>
<html>
<head>
<title>{block title}My App{/block}</title>
</head>
<body>
<header>...</header>
{include content}
<footer>...</footer>
</body>
</html>
I to będzie szablon akcji:
{block title}Homepage{/block}
{block content}
<h1>Homepage</h1>
...
{/block}
Definiuje blok content
, który zostanie wstawiony w miejsce {include content}
w układzie, a także
redefiniuje blok title
, który zastąpi {block title}
w układzie. Spróbujcie sobie wyobrazić ten
rezultat.
Wyszukiwanie szablonów
Ścieżka do szablonów jest wyprowadzana przez prezentera za pomocą prostej logiki. Spróbuje sprawdzić, czy jeden z tych
plików znajduje się relatywnie od katalogu klasy prezentera, gdzie <Presenter>
to nazwa aktualnego
prezentera, a <view>
jest nazwą bieżącego zdarzenia:
templates/<Presenter>/<view>.latte
templates/<Presenter>.<view>.latte
Jeśli szablon nie zostanie znaleziony, spróbuje poszukać w katalogu templates
o jeden poziom wyżej, czyli na
tym samym poziomie co katalog z klasą prezentera.
Jeśli tam również nie zostanie znaleziony szablon, odpowiedzią będzie błąd 404.
Widok można również zmienić za pomocą strony $this->setView('jineView')
. Lub, zamiast szukać
bezpośrednio, określ nazwę pliku szablonu za pomocą
$this->template->setFile('/path/to/template.latte')
.
Pliki, w których wyszukiwane są szablony można zmienić nakładając na metodę formatTemplateFiles(), która zwraca tablicę możliwych nazw plików.
W tych plikach spodziewany jest układ:
templates/<Presenter>/@<layout>.latte
templates/<Presenter>.@<layout>.latte
templates/@<layout>.latte
układ wspólny dla wielu prezenterów
Gdzie <Presenter>
to nazwa aktualnego prezentera, a <layout>
jest nazwą układu, którą
domyślnie jest 'layout'
. Nazwę można zmienić za pomocą $this->setLayout('jinyLayout')
, więc
wypróbowane zostaną pliki @jinyLayout.latte
.
Możesz również bezpośrednio określić nazwę pliku szablonu układu, używając
$this->setLayout('/path/to/template.latte')
. Użycie $this->setLayout(false)
wyłączy śledzenie
układu.
Pliki, w których wyszukiwane są szablony układów można zmienić nakładając na metodę formatLayoutTemplateFiles(), która zwraca tablicę możliwych nazw plików.
Zmienne w szablonie
Zmienne są przekazywane do szablonu poprzez zapisanie ich do $this->template
, a następnie są dostępne w
szablonie jako zmienne lokalne:
$this->template->article = $this->articles->getById($id);
W ten sposób możemy łatwo przekazać dowolne zmienne do szablonów. Jednak podczas tworzenia solidnych aplikacji często bardziej przydatne jest ograniczenie się. Na przykład poprzez jawne zdefiniowanie listy zmiennych, których oczekuje szablon i ich typów. Pozwoli to PHP na sprawdzanie typu, IDE na prawidłowe szeptanie, a analiza statyczna na wykrywanie błędów.
A jak zdefiniować taką wyliczankę? Po prostu w postaci klasy i jej właściwości. Nazwiemy go jak presenter, ale z
Template
na końcu:
/**
* @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;
// a další proměnné
}
Obiekt $this->template
w prezenterze będzie teraz instancją klasy ArticleTemplate
. Tak więc PHP
będzie sprawdzać zadeklarowane typy podczas pisania. A począwszy od PHP 8.2, będzie również ostrzegać przy zapisie do
nieistniejącej zmiennej; w poprzednich wersjach to samo można osiągnąć za pomocą cechy Nette\SmartObject.
Adnotacja @property-read
jest dla IDE i analizy statycznej, sprawi, że szeptanie będzie działać, zobacz PhpStorm i uzupełnianie kodu dla
$this->template.

Możesz również mieć luksus szeptania w szablonach, wystarczy zainstalować wtyczkę Latte w PhpStorm i umieścić nazwę klasy na początku szablonu, zobacz artykuł Latte: jak wpisać system, aby uzyskać więcej informacji:
{templateType App\Presenters\ArticleTemplate}
...
W ten sam sposób działają szablony w komponentach, wystarczy zastosować konwencję nazewnictwa i stworzyć klasę szablonu
FifteenTemplate
dla komponentu np. FifteenControl
.
Jeśli potrzebujesz stworzyć $template
jako instancję innej klasy, użyj metody
createTemplate()
:
public function renderDefault(): void
{
$template = $this->createTemplate(SpecialTemplate::class);
$template->foo = 123;
// ...
$this->sendTemplate($template);
}
Zmienne domyślne
Prezentery i komponenty przekazują automatycznie kilka przydatnych zmiennych do szablonów:
$basePath
to bezwzględna ścieżka URL do katalogu głównego (np./eshop
)$baseUrl
to bezwzględny adres URL do katalogu głównego (np.http://localhost/eshop
)$user
jest obiektem reprezentującym użytkownika$presenter
jest obecnym prezenterem$control
jest bieżącym elementem lub prezenterem$flashes
jest tablicą wiadomości wysyłanych przez funkcjeflashMessage()
Jeśli używasz niestandardowej klasy szablonu, te zmienne zostaną przekazane, jeśli utworzysz dla nich właściwość.
Tworzenie linków
Szablon tworzy w ten sposób linki do innych prezenterów & wydarzeń:
<a n:href="Product:show">detail produktu</a>
Atrybut n:href
jest bardzo przydatny dla znaczników HTML <a>
. Jeśli chcemy wymienić link w
innym miejscu, na przykład w tekście, używamy {link}
:
Adresa je: {link Home:default}
Aby uzyskać więcej informacji, zobacz Tworzenie linków URL.
Niestandardowe filtry, tagi, itp.
System szablonów Latte może być rozszerzony o własne filtry, funkcje, tagi, itp. Można to zrobić bezpośrednio w
metodzie render<View>
lub beforeRender()
:
public function beforeRender(): void
{
// dodaj filtr
$this->template->addFilter('foo', /* ... */);
// lub skonfigurować bezpośrednio obiekt Latte\Engine
$latte = $this->template->getLatte();
$latte->addFilterLoader(/* ... */);
}
Latte w wersji 3 oferuje bardziej zaawansowany sposób tworzenia rozszerzenia dla każdego projektu internetowego. Oto krótki przykład takiej klasy:
namespace App\Templating;
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()),
// ...
];
}
// ...
}
Rejestrujemy go za pomocą konfiguracji:
latte:
extensions:
- App\Templating\LatteExtension
Tłumaczenie
Jeśli programujesz wielojęzyczną aplikację, prawdopodobnie będziesz musiał wyprowadzić część tekstu w szablonie w
różnych językach. Aby to zrobić, Nette Framework definiuje interfejs tłumaczący Nette\Localization\Translator, który posiada
pojedynczą metodę translate()
. Przyjmuje ona komunikat $message
, który zwykle jest ciągiem znaków,
oraz dowolne inne parametry. Jej zadaniem jest zwrócenie przetłumaczonego ciągu znaków. W Nette nie ma domyślnej
implementacji, można wybrać według własnych potrzeb spośród kilku gotowych rozwiązań, które można znaleźć na Componette. Ich dokumentacja podpowiada, jak skonfigurować translator.
Szablony można skonfigurować z tłumaczem, którego będziemy mieli przekazanego, za pomocą metody
setTranslator()
:
protected function beforeRender(): void
{
// ...
$this->template->setTranslator($translator);
}
Alternatywnie, tłumacz może być ustawiony za pomocą konfiguracji:
latte:
extensions:
- Latte\Essential\TranslatorExtension
Translator może być wtedy użyty np. jako filtr |translate
, z dodatkowymi parametrami przekazywanymi do metody
translate()
(patrz foo, bar
):
<a href="basket">{='Basket'|translate}</a>
<span>{$item|translate}</span>
<span>{$item|translate, foo, bar}</span>
Albo jako znacznik podkreślenia:
<a href="basket">{_'Basket'}</a>
<span>{_$item}</span>
<span>{_$item, foo, bar}</span>
Do tłumaczenia sekcji szablonu służy sparowany tag {translate}
(od wersji Latte 2.11, wcześniej używany był
tag {_}
):
<a href="order">{translate}Order{/translate}</a>
<a href="order">{translate foo, bar}Order{/translate}</a>
Translator jest domyślnie wywoływany w trybie runtime podczas renderowania szablonu. Latte w wersji 3 może jednak tłumaczyć cały tekst statyczny podczas kompilacji szablonu. Oszczędza to wydajność, ponieważ każdy ciąg jest tłumaczony tylko raz, a wynikowe tłumaczenie jest zapisywane do skompilowanej postaci. Tworzy to wiele skompilowanych wersji szablonu w katalogu cache, po jednej dla każdego języka. Aby to zrobić, musisz tylko określić język jako drugi parametr:
protected function beforeRender(): void
{
// ...
$this->template->setTranslator($translator, $lang);
}
Przez tekst statyczny rozumiemy na przykład {_'hello'}
lub {translate}hello{/translate}
. Tekst
niestatyczny, taki jak {_$foo}
, będzie nadal kompilowany w locie.