Nette Documentation Preview

syntax
Rozszerzanie Latte
******************

.[perex]
Latte zostało zaprojektowane z myślą o rozszerzalności. Chociaż jego standardowy zestaw znaczników, filtrów i funkcji obejmuje wiele przypadków użycia, często trzeba dodać własną, specyficzną logikę lub narzędzia pomocnicze. Ta strona zawiera przegląd sposobów rozszerzenia Latte, aby idealnie pasowało do wymagań Twojego projektu - od prostych pomocników po złożoną nową składnię.


Sposoby rozszerzania Latte
==========================

Oto szybki przegląd głównych sposobów dostosowywania i rozszerzania Latte:

- **[Filtry niestandardowe |Custom Filters]:** Do formatowania lub przekształcania danych bezpośrednio w wyjściu szablonu (np. `{$var|myFilter}`). Idealne do zadań takich jak formatowanie dat, modyfikacje tekstu lub stosowanie specyficznego escapowania. Można je również użyć do modyfikacji większych bloków zawartości HTML, opakowując zawartość w anonimowy [`{block}` |tags#block] i stosując na nim własny filtr.
- **[Funkcje niestandardowe |Custom Functions]:** Do dodawania logiki wielokrotnego użytku, którą można wywoływać w wyrażeniach w szablonie (np. `{myFunction($arg1, $arg2)}`). Przydatne do obliczeń, dostępu do funkcji pomocniczych aplikacji lub generowania małych fragmentów treści.
- **[Znaczniki niestandardowe |Custom Tags]:** Do tworzenia zupełnie nowych konstrukcji językowych (`{mytag}...{/mytag}` lub `n:mytag`). Znaczniki oferują najwięcej możliwości, pozwalają definiować własne struktury, kontrolować parsowanie szablonu i implementować złożoną logikę renderowania.
- **[Przejścia kompilatora |Compiler Passes]:** Funkcje, które modyfikują abstrakcyjne drzewo składni (AST) szablonu po parsowaniu, ale przed generowaniem kodu PHP. Używane do zaawansowanych optymalizacji, kontroli bezpieczeństwa (takich jak Sandbox) lub automatycznych modyfikacji kodu.
- **[Niestandardowe loadery |loaders]:** Do zmiany sposobu, w jaki Latte wyszukuje i ładuje pliki szablonów (np. ładowanie z bazy danych, zaszyfrowanego magazynu itp.).

Wybór odpowiedniej metody rozszerzenia jest kluczowy. Zanim stworzysz złożony znacznik, zastanów się, czy nie wystarczyłby prostszy filtr lub funkcja. Pokażmy to na przykładzie: implementacja generatora *Lorem ipsum*, który jako argument przyjmuje liczbę słów do wygenerowania.

- **Jako znacznik?** `{lipsum 40}` - Możliwe, ale znaczniki są bardziej odpowiednie dla struktur sterujących lub generowania złożonych znaczników. Znaczników nie można używać bezpośrednio w wyrażeniach.
- **Jako filtr?** `{=40|lipsum}` - Technicznie to działa, ale filtry są przeznaczone do *transformacji* wartości wejściowej. Tutaj `40` jest *argumentem*, a nie wartością, która jest transformowana. To wydaje się semantycznie niepoprawne.
- **Jako funkcja?** `{lipsum(40)}` - To jest najbardziej naturalne rozwiązanie! Funkcje przyjmują argumenty i zwracają wartości, co jest idealne do użycia w dowolnym wyrażeniu: `{var $text = lipsum(40)}`.

**Ogólne zalecenie:** Używaj funkcji do obliczeń/generowania, filtrów do transformacji i znaczników do nowych konstrukcji językowych lub złożonych znaczników. Przejść używaj do manipulacji AST, a loaderów do pobierania szablonów.


Bezpośrednia rejestracja
========================

Dla narzędzi pomocniczych specyficznych dla projektu lub szybkich rozszerzeń, Latte umożliwia bezpośrednią rejestrację filtrów i funkcji w obiekcie `Latte\Engine`.

Do rejestracji filtra użyj metody `addFilter()`. Pierwszym argumentem Twojej funkcji filtrującej będzie wartość przed znakiem `|`, a kolejne argumenty to te, które są przekazywane za dwukropkiem `:`.

```php
$latte = new Latte\Engine;

// Definicja filtra (obiekt wywoływalny: funkcja, metoda statyczna itp.)
$myTruncate = fn(string $s, int $length = 50) => mb_substr($s, 0, $length);

// Rejestracja
$latte->addFilter('truncate', $myTruncate);

// Użycie w szablonie: {$text|truncate} lub {$text|truncate:100}
```

Możesz również zarejestrować **Filter Loader**, funkcję, która dynamicznie dostarcza obiekty wywoływalne filtrów według żądanej nazwy:

```php
$latte->addFilterLoader(fn(string $name) => /* zwraca obiekt wywoływalny lub null */);
```


Do rejestracji funkcji użytecznej w wyrażeniach szablonu użyj `addFunction()`.

```php
$latte = new Latte\Engine;

// Definicja funkcji
$isWeekend = fn(DateTimeInterface $date) => $date->format('N') >= 6;

// Rejestracja
$latte->addFunction('isWeekend', $isWeekend);

// Użycie w szablonie: {if isWeekend($myDate)}Weekend!{/if}
```

Więcej informacji znajdziesz w części [Tworzenie niestandardowych filtrów |custom-filters] i [Funkcji |custom-functions].


Solidny sposób: Rozszerzenie Latte .{toc: Latte Extension}
==========================================================

Chociaż bezpośrednia rejestracja jest prosta, standardowym i zalecanym sposobem pakowania i dystrybucji rozszerzeń Latte jest użycie klas **Extension**. Extension służy jako centralny punkt konfiguracyjny do rejestracji wielu znaczników, filtrów, funkcji, przejść kompilatora i innych elementów.

Dlaczego używać Extensions?

- **Organizacja:** Utrzymuje powiązane rozszerzenia (znaczniki, filtry itp. dla konkretnej funkcji) razem w jednej klasie.
- **Wielokrotne użycie i udostępnianie:** Łatwo spakujesz swoje rozszerzenia do użytku w innych projektach lub do udostępnienia społeczności (np. przez Composer).
- **Pełna moc:** Niestandardowe znaczniki i przejścia kompilatora *mogą być rejestrowane tylko* za pośrednictwem Extensions.


Rejestracja Rozszerzenia
------------------------

Extension rejestruje się w Latte za pomocą metody `addExtension()` (lub za pośrednictwem [pliku konfiguracyjnego |application:configuration#Szablony Latte]):

```php
$latte = new Latte\Engine;
$latte->addExtension(new MyProjectExtension);
```

Jeśli zarejestrujesz wiele rozszerzeń i definiują one tak samo nazwane znaczniki, filtry lub funkcje, pierwszeństwo ma ostatnio dodane rozszerzenie. Oznacza to również, że Twoje rozszerzenia mogą nadpisywać natywne znaczniki/filtry/funkcje.

Za każdym razem, gdy dokonasz zmiany w klasie i automatyczne odświeżanie nie jest wyłączone, Latte automatycznie przekompiluje Twoje szablony.


Tworzenie Rozszerzenia
----------------------

Aby utworzyć własne rozszerzenie, musisz utworzyć klasę, która dziedziczy z [api:Latte\Extension]. Aby zobaczyć, jak wygląda takie rozszerzenie, spójrz na wbudowane "CoreExtension":https://github.com/nette/latte/blob/master/src/Latte/Essential/CoreExtension.php.

Przyjrzyjmy się metodom, które możesz zaimplementować:


beforeCompile(Latte\Engine $engine): void .[method]
---------------------------------------------------

Wywoływane przed kompilacją szablonu. Metoda może być używana na przykład do inicjalizacji związanych z kompilacją.


getTags(): array .[method]
--------------------------

Wywoływane podczas kompilacji szablonu. Zwraca tablicę asocjacyjną *nazwa znacznika => obiekt wywoływalny*, które są funkcjami do parsowania znaczników. [Więcej informacji |custom-tags].

```php
public function getTags(): array
{
	return [
		'foo' => FooNode::create(...),
		'bar' => BarNode::create(...),
		'n:baz' => NBazNode::create(...),
		// ...
	];
}
```

Znacznik `n:baz` reprezentuje czysty [n:atrybut |syntax#n:atrybuty], czyli znacznik, który można zapisać tylko jako atrybut.

Dla znaczników `foo` i `bar` Latte automatycznie rozpozna, czy są to znaczniki parzyste, a jeśli tak, można je automatycznie zapisywać za pomocą n:atrybutów, w tym wariantów z prefiksami `n:inner-foo` i `n:tag-foo`.

Kolejność wykonywania takich n:atrybutów jest określona przez ich kolejność w tablicy zwróconej przez metodę `getTags()`. Zatem `n:foo` jest zawsze wykonywany przed `n:bar`, nawet jeśli atrybuty w znaczniku HTML są wymienione w odwrotnej kolejności, jak `<div n:bar="..." n:foo="...">`.

Jeśli potrzebujesz określić kolejność n:atrybutów w wielu rozszerzeniach, użyj metody pomocniczej `order()`, gdzie parametr `before` xor `after` określa, które znaczniki są sortowane przed lub za znacznikiem.

```php
public function getTags(): array
{
	return [
		'foo' => self::order(FooNode::create(...), before: 'bar'),
		'bar' => self::order(BarNode::create(...), after: ['block', 'snippet']),
	];
}
```


getPasses(): array .[method]
----------------------------

Wywoływane podczas kompilacji szablonu. Zwraca tablicę asocjacyjną *nazwa przejścia => obiekt wywoływalny*, które są funkcjami reprezentującymi tzw. [przejścia kompilatora |compiler-passes], które przechodzą i modyfikują AST.

Tutaj również można użyć metody pomocniczej `order()`. Wartość parametrów `before` lub `after` może być `*` o znaczeniu przed/po wszystkich.

```php
public function getPasses(): array
{
	return [
		'optimize' => Passes::optimizePass(...),
		'sandbox' => self::order($this->sandboxPass(...), before: '*'),
		// ...
	];
}
```


beforeRender(Latte\Engine $engine): void .[method]
--------------------------------------------------

Wywoływane przed każdym renderowaniem szablonu. Metoda może być używana na przykład do inicjalizacji zmiennych używanych podczas renderowania.


getFilters(): array .[method]
-----------------------------

Wywoływane przed renderowaniem szablonu. Zwraca filtry jako tablicę asocjacyjną *nazwa filtra => obiekt wywoływalny*. [Więcej informacji |custom-filters].

```php
public function getFilters(): array
{
	return [
		'batch' => $this->batchFilter(...),
		'trim' => $this->trimFilter(...),
		// ...
	];
}
```


getFunctions(): array .[method]
-------------------------------

Wywoływane przed renderowaniem szablonu. Zwraca funkcje jako tablicę asocjacyjną *nazwa funkcji => obiekt wywoływalny*. [Więcej informacji |custom-functions].

```php
public function getFunctions(): array
{
	return [
		'clamp' => $this->clampFunction(...),
		'divisibleBy' => $this->divisibleByFunction(...),
		// ...
	];
}
```


getProviders(): array .[method]
-------------------------------

Wywoływane przed renderowaniem szablonu. Zwraca tablicę dostawców, którzy są zazwyczaj obiektami używanymi przez znaczniki w czasie działania. Dostęp do nich uzyskuje się przez `$this->global->...`. [Więcej informacji |custom-tags#Wprowadzenie providerów].

```php
public function getProviders(): array
{
	return [
		'myFoo' => $this->foo,
		'myBar' => $this->bar,
		// ...
	];
}
```


getCacheKey(Latte\Engine $engine): mixed .[method]
--------------------------------------------------

Wywoływane przed renderowaniem szablonu. Wartość zwracana staje się częścią klucza, którego hash jest zawarty w nazwie pliku skompilowanego szablonu. Dla różnych wartości zwracanych Latte wygeneruje więc różne pliki cache.

Rozszerzanie Latte

Latte zostało zaprojektowane z myślą o rozszerzalności. Chociaż jego standardowy zestaw znaczników, filtrów i funkcji obejmuje wiele przypadków użycia, często trzeba dodać własną, specyficzną logikę lub narzędzia pomocnicze. Ta strona zawiera przegląd sposobów rozszerzenia Latte, aby idealnie pasowało do wymagań Twojego projektu – od prostych pomocników po złożoną nową składnię.

Sposoby rozszerzania Latte

Oto szybki przegląd głównych sposobów dostosowywania i rozszerzania Latte:

  • Filtry niestandardowe: Do formatowania lub przekształcania danych bezpośrednio w wyjściu szablonu (np. {$var|myFilter}). Idealne do zadań takich jak formatowanie dat, modyfikacje tekstu lub stosowanie specyficznego escapowania. Można je również użyć do modyfikacji większych bloków zawartości HTML, opakowując zawartość w anonimowy {block} i stosując na nim własny filtr.
  • Funkcje niestandardowe: Do dodawania logiki wielokrotnego użytku, którą można wywoływać w wyrażeniach w szablonie (np. {myFunction($arg1, $arg2)}). Przydatne do obliczeń, dostępu do funkcji pomocniczych aplikacji lub generowania małych fragmentów treści.
  • Znaczniki niestandardowe: Do tworzenia zupełnie nowych konstrukcji językowych ({mytag}...{/mytag} lub n:mytag). Znaczniki oferują najwięcej możliwości, pozwalają definiować własne struktury, kontrolować parsowanie szablonu i implementować złożoną logikę renderowania.
  • Przejścia kompilatora: Funkcje, które modyfikują abstrakcyjne drzewo składni (AST) szablonu po parsowaniu, ale przed generowaniem kodu PHP. Używane do zaawansowanych optymalizacji, kontroli bezpieczeństwa (takich jak Sandbox) lub automatycznych modyfikacji kodu.
  • Niestandardowe loadery: Do zmiany sposobu, w jaki Latte wyszukuje i ładuje pliki szablonów (np. ładowanie z bazy danych, zaszyfrowanego magazynu itp.).

Wybór odpowiedniej metody rozszerzenia jest kluczowy. Zanim stworzysz złożony znacznik, zastanów się, czy nie wystarczyłby prostszy filtr lub funkcja. Pokażmy to na przykładzie: implementacja generatora Lorem ipsum, który jako argument przyjmuje liczbę słów do wygenerowania.

  • Jako znacznik? {lipsum 40} – Możliwe, ale znaczniki są bardziej odpowiednie dla struktur sterujących lub generowania złożonych znaczników. Znaczników nie można używać bezpośrednio w wyrażeniach.
  • Jako filtr? {=40|lipsum} – Technicznie to działa, ale filtry są przeznaczone do transformacji wartości wejściowej. Tutaj 40 jest argumentem, a nie wartością, która jest transformowana. To wydaje się semantycznie niepoprawne.
  • Jako funkcja? {lipsum(40)} – To jest najbardziej naturalne rozwiązanie! Funkcje przyjmują argumenty i zwracają wartości, co jest idealne do użycia w dowolnym wyrażeniu: {var $text = lipsum(40)}.

Ogólne zalecenie: Używaj funkcji do obliczeń/generowania, filtrów do transformacji i znaczników do nowych konstrukcji językowych lub złożonych znaczników. Przejść używaj do manipulacji AST, a loaderów do pobierania szablonów.

Bezpośrednia rejestracja

Dla narzędzi pomocniczych specyficznych dla projektu lub szybkich rozszerzeń, Latte umożliwia bezpośrednią rejestrację filtrów i funkcji w obiekcie Latte\Engine.

Do rejestracji filtra użyj metody addFilter(). Pierwszym argumentem Twojej funkcji filtrującej będzie wartość przed znakiem |, a kolejne argumenty to te, które są przekazywane za dwukropkiem :.

$latte = new Latte\Engine;

// Definicja filtra (obiekt wywoływalny: funkcja, metoda statyczna itp.)
$myTruncate = fn(string $s, int $length = 50) => mb_substr($s, 0, $length);

// Rejestracja
$latte->addFilter('truncate', $myTruncate);

// Użycie w szablonie: {$text|truncate} lub {$text|truncate:100}

Możesz również zarejestrować Filter Loader, funkcję, która dynamicznie dostarcza obiekty wywoływalne filtrów według żądanej nazwy:

$latte->addFilterLoader(fn(string $name) => /* zwraca obiekt wywoływalny lub null */);

Do rejestracji funkcji użytecznej w wyrażeniach szablonu użyj addFunction().

$latte = new Latte\Engine;

// Definicja funkcji
$isWeekend = fn(DateTimeInterface $date) => $date->format('N') >= 6;

// Rejestracja
$latte->addFunction('isWeekend', $isWeekend);

// Użycie w szablonie: {if isWeekend($myDate)}Weekend!{/if}

Więcej informacji znajdziesz w części Tworzenie niestandardowych filtrówFunkcji.

Solidny sposób: Rozszerzenie Latte

Chociaż bezpośrednia rejestracja jest prosta, standardowym i zalecanym sposobem pakowania i dystrybucji rozszerzeń Latte jest użycie klas Extension. Extension służy jako centralny punkt konfiguracyjny do rejestracji wielu znaczników, filtrów, funkcji, przejść kompilatora i innych elementów.

Dlaczego używać Extensions?

  • Organizacja: Utrzymuje powiązane rozszerzenia (znaczniki, filtry itp. dla konkretnej funkcji) razem w jednej klasie.
  • Wielokrotne użycie i udostępnianie: Łatwo spakujesz swoje rozszerzenia do użytku w innych projektach lub do udostępnienia społeczności (np. przez Composer).
  • Pełna moc: Niestandardowe znaczniki i przejścia kompilatora mogą być rejestrowane tylko za pośrednictwem Extensions.

Rejestracja Rozszerzenia

Extension rejestruje się w Latte za pomocą metody addExtension() (lub za pośrednictwem pliku konfiguracyjnego):

$latte = new Latte\Engine;
$latte->addExtension(new MyProjectExtension);

Jeśli zarejestrujesz wiele rozszerzeń i definiują one tak samo nazwane znaczniki, filtry lub funkcje, pierwszeństwo ma ostatnio dodane rozszerzenie. Oznacza to również, że Twoje rozszerzenia mogą nadpisywać natywne znaczniki/filtry/funkcje.

Za każdym razem, gdy dokonasz zmiany w klasie i automatyczne odświeżanie nie jest wyłączone, Latte automatycznie przekompiluje Twoje szablony.

Tworzenie Rozszerzenia

Aby utworzyć własne rozszerzenie, musisz utworzyć klasę, która dziedziczy z Latte\Extension. Aby zobaczyć, jak wygląda takie rozszerzenie, spójrz na wbudowane CoreExtension.

Przyjrzyjmy się metodom, które możesz zaimplementować:

beforeCompile(Latte\Engine $engine)void

Wywoływane przed kompilacją szablonu. Metoda może być używana na przykład do inicjalizacji związanych z kompilacją.

getTags(): array

Wywoływane podczas kompilacji szablonu. Zwraca tablicę asocjacyjną nazwa znacznika ⇒ obiekt wywoływalny, które są funkcjami do parsowania znaczników. Więcej informacji.

public function getTags(): array
{
	return [
		'foo' => FooNode::create(...),
		'bar' => BarNode::create(...),
		'n:baz' => NBazNode::create(...),
		// ...
	];
}

Znacznik n:baz reprezentuje czysty n:atrybut, czyli znacznik, który można zapisać tylko jako atrybut.

Dla znaczników foo i bar Latte automatycznie rozpozna, czy są to znaczniki parzyste, a jeśli tak, można je automatycznie zapisywać za pomocą n:atrybutów, w tym wariantów z prefiksami n:inner-foo i n:tag-foo.

Kolejność wykonywania takich n:atrybutów jest określona przez ich kolejność w tablicy zwróconej przez metodę getTags(). Zatem n:foo jest zawsze wykonywany przed n:bar, nawet jeśli atrybuty w znaczniku HTML są wymienione w odwrotnej kolejności, jak <div n:bar="..." n:foo="...">.

Jeśli potrzebujesz określić kolejność n:atrybutów w wielu rozszerzeniach, użyj metody pomocniczej order(), gdzie parametr before xor after określa, które znaczniki są sortowane przed lub za znacznikiem.

public function getTags(): array
{
	return [
		'foo' => self::order(FooNode::create(...), before: 'bar'),
		'bar' => self::order(BarNode::create(...), after: ['block', 'snippet']),
	];
}

getPasses(): array

Wywoływane podczas kompilacji szablonu. Zwraca tablicę asocjacyjną nazwa przejścia ⇒ obiekt wywoływalny, które są funkcjami reprezentującymi tzw. przejścia kompilatora, które przechodzą i modyfikują AST.

Tutaj również można użyć metody pomocniczej order(). Wartość parametrów before lub after może być * o znaczeniu przed/po wszystkich.

public function getPasses(): array
{
	return [
		'optimize' => Passes::optimizePass(...),
		'sandbox' => self::order($this->sandboxPass(...), before: '*'),
		// ...
	];
}

beforeRender(Latte\Engine $engine)void

Wywoływane przed każdym renderowaniem szablonu. Metoda może być używana na przykład do inicjalizacji zmiennych używanych podczas renderowania.

getFilters(): array

Wywoływane przed renderowaniem szablonu. Zwraca filtry jako tablicę asocjacyjną nazwa filtra ⇒ obiekt wywoływalny. Więcej informacji.

public function getFilters(): array
{
	return [
		'batch' => $this->batchFilter(...),
		'trim' => $this->trimFilter(...),
		// ...
	];
}

getFunctions(): array

Wywoływane przed renderowaniem szablonu. Zwraca funkcje jako tablicę asocjacyjną nazwa funkcji ⇒ obiekt wywoływalny. Więcej informacji.

public function getFunctions(): array
{
	return [
		'clamp' => $this->clampFunction(...),
		'divisibleBy' => $this->divisibleByFunction(...),
		// ...
	];
}

getProviders(): array

Wywoływane przed renderowaniem szablonu. Zwraca tablicę dostawców, którzy są zazwyczaj obiektami używanymi przez znaczniki w czasie działania. Dostęp do nich uzyskuje się przez $this->global->.... Więcej informacji.

public function getProviders(): array
{
	return [
		'myFoo' => $this->foo,
		'myBar' => $this->bar,
		// ...
	];
}

getCacheKey(Latte\Engine $engine)mixed

Wywoływane przed renderowaniem szablonu. Wartość zwracana staje się częścią klucza, którego hash jest zawarty w nazwie pliku skompilowanego szablonu. Dla różnych wartości zwracanych Latte wygeneruje więc różne pliki cache.