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}
lubn: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. Tutaj40
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ów i Funkcji.
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.