Dziedziczenie i możliwość ponownego wykorzystania szablonów
Mechanizmy ponownego wykorzystania szablonów i dziedziczenia zwiększą Twoją produktywność, ponieważ każdy szablon zawiera tylko swoją unikalną zawartość, a powtarzające się elementy i struktury zostaną ponownie wykorzystane. Wprowadzamy trzy pojęcia: dziedziczenie układu, ponowne wykorzystanie poziome oraz dziedziczenie jednostkowe.
Koncepcja dziedziczenia szablonów Latte jest podobna do dziedziczenia klas w PHP. Definiujesz szablon nadrzędny, z którego inne szablony podrzędne mogą dziedziczyć i mogą nadpisywać części szablonu nadrzędnego. Działa to świetnie, gdy elementy mają wspólną strukturę. Brzmi skomplikowanie? Nie martw się, to bardzo proste.
Dziedziczenie układu {layout}
Przyjrzyjmy się na przykładzie dziedziczenia szablonu układu, czyli layoutu. Jest to szablon nadrzędny, który nazwiemy na
przykład layout.latte
, a który definiuje szkielet dokumentu HTML:
Znaczniki {block}
definiują trzy bloki, które mogą wypełnić szablony dziecięce. Znacznik block nie robi nic
więcej niż oznajmia, że to miejsce może być nadpisane przez szablon dziecka poprzez zdefiniowanie własnego bloku o tej
samej nazwie.
Szablon dziecka może wyglądać tak:
Kluczem jest tutaj tag {layout}
. Latte mówi, że ten szablon „rozszerza“ inny szablon. Kiedy Latte renderuje
ten szablon, najpierw znajduje rodzica – w tym przypadku layout.latte
.
W tym momencie Latte zauważa trzy znaczniki bloków w layout.latte
i zastępuje te bloki zawartością szablonu
dziecka. Ponieważ szablon dziecka nie zdefiniował bloku footer, zamiast niego używana jest zawartość z szablonu
rodzica. Zawartość w tagu {block}
w szablonie nadrzędnym jest zawsze używana jako fallback.
Dane wyjściowe mogą wyglądać tak:
W szablonie dziecka bloki mogą być umieszczane tylko na najwyższym poziomie lub wewnątrz innego bloku, tj :
Ponadto blok zostanie zawsze utworzony niezależnie od tego, czy otaczający go warunek {if}
oceniany jest jako
prawdziwy czy fałszywy. Więc nawet jeśli nie wygląda, to ten szablon zdefiniuje blok.
Jeśli chcesz, aby wyjście wewnątrz bloku pojawiło się warunkowo, użyj zamiast tego następującego:
Rozmieść bloki w szablonie dziecka przed renderowaniem szablonu układu, abyś mógł użyć ich do zdefiniowania zmiennych,
takich jak {var $foo = bar}
i propagować dane do całego łańcucha dziedziczenia:
Dziedziczenie wielopoziomowe
Możesz użyć tylu poziomów dziedziczenia, ile potrzebujesz. Powszechnym sposobem korzystania z dziedziczenia układu jest następujące trzypoziomowe podejście:
- Utwórz szablon
layout.latte
, który zawiera główny szkielet wyglądu strony. - Utwórz szablon
layout-SECTIONNAME.latte
dla każdej sekcji swojej strony. Na przykład:layout-news.latte
,layout-blog.latte
, itd. Wszystkie te szablony rozszerzająlayout.latte
i zawierają style & design specyficzne dla każdej sekcji. - Utwórz indywidualne szablony dla każdego typu strony, np. artykułu prasowego lub wpisu na blogu. Szablony te rozszerzają odpowiedni szablon sekcji.
Dynamiczne dziedziczenie
Zmienna lub dowolne wyrażenie PHP może być użyte jako nazwa szablonu nadrzędnego, więc dziedziczenie może zachowywać się dynamicznie:
Możesz również użyć interfejsu API Latte, aby automatycznie wybrać szablon układu.
Porady
Oto kilka wskazówek dotyczących pracy z dziedziczeniem układów:
- Jeśli używasz
{layout}
w szablonie , musi to być pierwszy tag szablonu w tym szablonie. - Układ może być wyszukiwany automatycznie (jak w prezenterach). W takim przypadku, jeśli szablon nie
powinien mieć układu, wskaże to za pomocą znacznika
{layout none}
. - Znacznik
{layout}
ma alias{extends}
. - Nazwa pliku układu zależy od programu ładującego.
- Możesz mieć tyle bloków, ile chcesz. Zauważ, że szablony dzieci nie muszą definiować wszystkich bloków nadrzędnych, więc możesz wypełnić rozsądne domyślne ustawienia w kilku blokach, a następnie zdefiniować tylko te, których potrzebujesz później.
Bloki {block}
Zobacz także anonimowość {block}
Blok jest sposobem na zmianę sposobu renderowania pewnej części szablonu, ale nie ingeruje w logikę wokół niego. W poniższym przykładzie pokażemy jak działa blok, ale też jak nie działa:
Jeśli wyrenderujesz ten szablon, wynik będzie dokładnie taki sam z i bez znaczników {block}
. Bloki mają
dostęp do zmiennych z zewnętrznych zakresów. Po prostu dają opcję do nadpisania przez szablon dziecka:
Teraz podczas renderowania szablonu dziecięcego pętla użyje bloku zdefiniowanego w szablonie dziecięcym
child.Latte
zamiast bloku zdefiniowanego w parent.Latte
; działający szablon ma wtedy odpowiednik:
Jeśli jednak utworzymy nową zmienną wewnątrz nazwanego bloku lub zastąpimy wartość istniejącej, zmiana będzie widoczna tylko wewnątrz bloku:
Zawartość bloku może być modyfikowana za pomocą filtrów. Poniższy przykład usuwa cały HTML i zmienia wielkość liter:
Znacznik może być również zapisany jako n:attribut:
Bloki lokalne
Każdy blok nadpisuje zawartość bloku nadrzędnego o tej samej nazwie – z wyjątkiem bloków lokalnych. W klasach byłoby to coś w rodzaju prywatnych metod. Możesz więc stworzyć szablon bez obaw, że z powodu zgodności nazw bloków zostaną one nadpisane z innego szablonu.
Rendering bloków {include}
Zobacz także. {include file}
Aby wymienić blok w konkretnym miejscu, należy użyć znacznika {include blockname}
:
Można również wylistować blok z innego szablonu:
Wyrenderowany blok nie ma dostępu do aktywnych zmiennych kontekstowych, z wyjątkiem sytuacji, gdy blok jest zdefiniowany w tym samym pliku, w którym został wstawiony. Ma jednak dostęp do zmiennych globalnych.
Do bloku można przekazać zmienne w następujący sposób:
Jako nazwy bloku możesz użyć zmiennej lub dowolnego wyrażenia PHP. W tym przypadku dodajemy słowo kluczowe
block
przed zmienną, aby w czasie kompilacji Latte wiedziało już, że chodzi o blok, a nie o wstawienie szablonu, którego nazwa również mogłaby znaleźć się w zmiennej:
Blok może być również renderowany wewnątrz siebie, co jest przydatne na przykład przy renderowaniu struktury drzewa:
Zamiast {include menu, ...}
, możemy napisać {include this, ...}
, gdzie this
oznacza
bieżący blok.
Wyrenderowany blok może być modyfikowany za pomocą filtrów. Poniższy przykład usuwa cały HTML i zmienia wielkość liter:
Blok macierzysty
Jeśli potrzebujesz zrzucić zawartość bloku z szablonu nadrzędnego, użyj {include parent}
. Jest to
przydatne, jeśli chcesz tylko dodać zawartość bloku nadrzędnego zamiast całkowicie go nadpisywać.
Definicja: {define}
Oprócz bloków, w Latte są też „definicje“. W normalnych językach programowania przyrównalibyśmy je do funkcji. Są one przydatne do ponownego wykorzystania fragmentów szablonów, aby nie powtarzać się.
Latte stara się zachować prostotę, więc zasadniczo definicje są takie same jak bloki, a wszystko, co powiedziano o blokach, dotyczy również definicji. Różnią się one od bloków tym:
- są zamknięte w tagach
{define}
- są renderowane tylko wtedy, gdy są wstawiane przez
{include}
- można definiować dla nich parametry, tak jak funkcje w PHP
Wyobraź sobie, że masz szablon pomocniczy z kolekcją definicji dotyczących rysowania formularzy HTML.
Argumenty definicji są zawsze opcjonalne z wartością domyślną null
, chyba że określono wartość
domyślną (tutaj 'text'
jest wartością domyślną dla $type
). Typy parametrów mogą być również
zadeklarowane: {define input, string $name, ...}
.
Szablon z definicjami jest ładowany przy użyciu {import}
. Same definicje
są renderowane w taki sam sposób jak bloki:
Definicje nie mają dostępu do zmiennych aktywnego kontekstu, ale mają dostęp do zmiennych globalnych.
Dynamiczne nazwy bloków
Latte pozwala na dużą elastyczność w definiowaniu bloków, ponieważ nazwa bloku może być dowolnym wyrażeniem PHP. W tym
przykładzie zdefiniowano trzy bloki o nazwach hi-Peter
, hi-John
, oraz hi-Mary
:
Możemy wtedy przedefiniować tylko jeden blok w szablonie dziecka, np:
Więc wyjście będzie wyglądać tak:
Sprawdź, czy istnieją bloki {ifset}
Zobacz także. {ifset $var}
Użyj testu {ifset blockname}
, aby sprawdzić, czy blok (lub wiele bloków) istnieje w bieżącym kontekście:
Nazwa bloku może być zmienną lub dowolnym wyrażeniem PHP. W tym przypadku dodajemy słowo kluczowe block
przed
zmienną, aby wyjaśnić, że nie jest to test na istnienie zmiennych:
Istnienie bloków jest również zwracane przez funkcję hasBlock()
:
Porady
Kilka wskazówek dotyczących pracy z klockami:
- Ostatni blok najwyższego poziomu nie musi mieć znacznika zamykającego (blok kończy się na końcu dokumentu). Upraszcza to pisanie szablonów dzieci, które zawierają jeden blok główny.
- Dla lepszej czytelności można zawrzeć nazwę bloku w znaczniku
{/block}
, na przykład{/block footer}
. Nazwa ta musi jednak odpowiadać nazwie bloku. W większych szablonach ta technika pomaga określić, które znaczniki blokowe zamykają. - Nie można bezpośrednio zdefiniować wielu znaczników blokowych o tej samej nazwie w tym samym szablonie. Można to jednak osiągnąć poprzez zastosowanie dynamicznych nazw bloków.
- Możesz użyć n:attributes do zdefiniowania bloków
jako
<h1 n:block=title>Welcome to my awesome homepage</h1>
- Możesz również użyć bloków bez nazw tylko do zastosowania filtrów:
{block|strip} hello {/block}
Ponowne wykorzystanie poziome {import}
Horyzontalne ponowne użycie jest trzecim mechanizmem ponownego użycia i dziedziczenia w Latte. Pozwala on na ładowanie
bloków z innych szablonów. Jest to podobne do tworzenia pliku z funkcjami pomocniczymi w PHP, a następnie ładowania go za
pomocą require
.
Dziedziczenie układu szablonu jest jedną z najpotężniejszych funkcji Latte, ale jest ograniczone do prostego dziedziczenia – szablon może rozszerzyć tylko jeden inny szablon. Ponowne użycie horyzontalne jest sposobem na osiągnięcie wielokrotnego dziedziczenia.
Weźmy zestaw definicji bloków:
Używając polecenia {import}
, zaimportuj wszystkie bloki i definicje zdefiniowane
w blocks.latte
do innego szablonu:
Jeśli zaimportujesz bloki w szablonie nadrzędnym (np. użyj {import}
w layout.latte
), bloki będą
również dostępne we wszystkich szablonach podrzędnych, co jest bardzo przydatne.
Szablon, który ma zostać zaimportowany (np. blocks.latte
) nie może rozszerzać innego szablonu, tj. używać {layout}
. Może on jednak importować
inne szablony.
Znacznik {import}
powinien być pierwszym znacznikiem szablonu po {layout}
. Nazwa szablonu może być
dowolnym wyrażeniem PHP:
W szablonie możesz użyć dowolnej ilości oświadczeń {import}
. Jeśli dwa importowane szablony definiują ten
sam blok, wygrywa pierwszy. Jednak szablon główny ma najwyższy priorytet i może zastąpić każdy zaimportowany blok.
Zawartość nadpisanych bloków można zachować, wstawiając blok w taki sam sposób, jak blok nadrzędny:
W tym przykładzie {include parent}
wywołuje blok sidebar
z szablonu blocks.latte
.
Dziedziczenie jednostek {embed}
Dziedziczenie jednostek rozszerza ideę dziedziczenia układu na poziom fragmentów treści. Podczas gdy dziedziczenie układu działa z „szkieletem dokumentu“, który jest animowany przez szablony dzieci, dziedziczenie jednostek pozwala na tworzenie szkieletów dla mniejszych jednostek treści i ponowne wykorzystanie ich gdziekolwiek chcesz.
W dziedziczeniu jednostek kluczem jest znacznik {embed}
. Łączy w sobie zachowanie {include}
i
{layout}
. Pozwala na wstawienie treści innego szablonu lub bloku i opcjonalnie przekazanie zmiennych, jak w
przypadku {include}
. Pozwala również na nadpisanie dowolnego bloku zdefiniowanego wewnątrz wstawionego szablonu,
tak jak w przypadku użycia {layout}
.
Na przykład używamy elementu accordion. Przyjrzyjmy się szkieletowi elementu zapisanego w szablonie
collapsible.latte
:
Znaczniki {block}
definiują dwa bloki, które szablony dziecięce mogą wypełnić. Tak, jak w przypadku szablonu
nadrzędnego w dziedziczeniu układu. Można też zobaczyć zmienną $modifierClass
.
Wykorzystajmy nasz element w szablonie. Tu z pomocą przychodzi {embed}
. Jest to niezwykle potężny znacznik,
który pozwala nam robić różne rzeczy: wstawiać zawartość elementu szablonu, dodawać do niego zmienne oraz dodawać bloki
z niestandardowym HTML:
Dane wyjściowe mogą wyglądać tak:
Bloki wewnątrz osadzonych znaczników tworzą osobną warstwę niezależną od pozostałych bloków. Dlatego mogą mieć taką
samą nazwę jak blok poza wstawką i nie są w żaden sposób dotknięte. Używając znacznika include wewnątrz znaczników {embed}
, można wstawiać bloki utworzone tutaj, bloki
z szablonu osadzonego (które nie są lokalne) oraz bloki z szablonu głównego, które
są lokalne. Można również importować bloki z innych plików:
Szablony wbudowane nie mają dostępu do aktywnych zmiennych kontekstowych, ale mają dostęp do zmiennych globalnych.
Nie tylko szablony, ale także inne bloki można wstawiać za pomocą {embed}
, więc poprzedni przykład można
było napisać w ten sposób:
Jeśli do {embed}
przekazujemy wyrażenie i nie jest jasne, czy chodzi o nazwę bloku czy pliku, dodajemy słowo
kluczowe block
lub file
:
Przypadki użycia
W Latte istnieją różne rodzaje dziedziczenia i ponownego wykorzystania kodu. Dla jasności podsumujmy główne pojęcia:
{include template}
Przypadek użycia: Użycie header.latte
i footer.latte
wewnątrz
layout.latte
.
header.latte
footer.latte
layout.latte
{layout}
Przypadek użycia: Rozszerzenie layout.latte
wewnątrz homepage.latte
i
about.latte
.
layout.latte
homepage.latte
about.latte
{import}
Przypadek użycia: sidebar.latte
w single.product.latte
i
single.service.latte
.
sidebar.latte
single.product.latte
single.service.latte
{define}
Użytek: Funkcja, do której przekazujemy zmienne i renderuje coś.
form.latte
profile.service.latte
{embed}
Przypadek użycia: Wstaw pagination.latte
do product.table.latte
i
service.table.latte
.
pagination.latte
product.table.latte
service.table.latte