Наследяване на шаблони и възможност за повторно използване
Механизмите за повторна употреба и наследяване на шаблони увеличават производителността ви, тъй като всеки шаблон съдържа само уникално съдържание, а повтарящите се елементи и структури се използват повторно. Въвеждаме три концепции: наследяване на оформлението, хоризонтално повторно използване и наследяване на единици.
Концепцията за наследяване на шаблони Latte е подобна на тази за наследяване на класове в PHP. Дефинирате шаблон-родител, от който други наследени шаблони могат да надграждат и да отменят части от шаблона-родител. Това работи чудесно, когато елементите имат обща структура. Звучи сложно? Не се притеснявайте, не е така.
Наследяване на оформлението {layout}
Нека разгледаме наследяването на шаблона на оформлението с пример.
Това е родителският шаблон, който в примера ще наречем layout.latte
, и
той определя HTML скелета на документа.
Тагът {block}
дефинира три блока, които подчинените шаблони могат
да попълват. Единственото, което тагът за блок прави, е да укаже на
шаблониращата машина, че подчиненият шаблон може да замени тези части
на шаблона, като дефинира свой собствен блок със същото име.
Един шаблон на дете може да изглежда по следния начин:
Ключовият етикет тук е {layout}
. Той указва на шаблониращата
машина, че този шаблон „разширява“ друг шаблон. Когато Latte визуализира
този шаблон, той първо намира родителя – в случая layout.latte
.
В този момент механизмът за шаблониране ще забележи три блокови тага
в layout.latte
и ще замени тези блокове със съдържанието на
подчинения шаблон. Имайте предвид, че тъй като шаблонът на детето не е
дефинирал блок footer, вместо него се използва съдържанието на
шаблона на родителя. Съдържанието в тага {block}
в родителския
шаблон винаги се използва като резервен вариант.
Изходът може да изглежда по следния начин:
В подчинен шаблон блоковете могат да се поставят само на горното ниво или в друг блок, т.е:
Освен това блокът винаги ще бъде създаден, независимо дали
заобикалящото го условие {if}
е оценено като вярно или невярно.
Противно на това, което си мислите, този шаблон дефинира блок.
Ако искате изходът в блока да се показва условно, използвайте следното:
Извънблоковите данни в подчинения шаблон се изпълняват преди
шаблонът за оформление да бъде визуализиран, така че можете да го
използвате, за да дефинирате променливи от тип {var $foo = bar}
и да
разпространявате данните по цялата верига на наследяване:
Наследяване на няколко нива
Можете да използвате толкова нива на наследяване, колкото ви е необходимо. Един от разпространените начини за използване на наследяване на оформлението е следният подход на три нива:
- Създайте шаблон
layout.latte
, в който се съхранява основният външен вид на сайта ви. - Създайте шаблон
layout-SECTIONNAME.latte
за всеки раздел на сайта си. Напримерlayout-news.latte
,layout-blog.latte
и т.н. Всички тези шаблони разширяватlayout.latte
и включват стилове/дизайни за всеки раздел. - Създайте отделни шаблони за всеки тип страница, например новинарска статия или публикация в блог. Тези шаблони разширяват съответния шаблон на раздела.
Динамично наследяване на оформлението
Можете да използвате променлива или какъвто и да е израз на PHP като име на родителския шаблон, така че наследяването да се извършва динамично:
Можете също така да използвате приложния програмен интерфейс Latte API за автоматично избиране на шаблона за оформление.
Съвети
Ето няколко съвета за работа с наследяване на оформлението:
- Ако използвате
{layout}
в шаблон, той трябва да бъде първият таг на шаблона в този шаблон. - Макетът може да се търси автоматично
(както в презентаторите). В
този случай, ако шаблонът не трябва да има оформление, той ще посочи
това с тага
{layout none}
. - Тагът
{layout}
има псевдоним{extends}
. - Името на разширения файл на шаблона зависи от програмата за зареждане на шаблони.
- Можете да имате толкова блокове, колкото искате. Не забравяйте, че не е задължително подчинените шаблони да дефинират всички родителски блокове, така че можете да въведете разумни стойности по подразбиране в няколко блока и след това да дефинирате само тези, които са ви необходими по-късно.
Блокове {block}
Вижте също анонимни {block}
Блокът ви позволява да променяте показването на определена част от шаблона, но не се намесва по никакъв начин в заобикалящата го логика. Нека разгледаме следния пример, за да илюстрираме как работи блокът и, което е по-важно, как не работи:
Ако покажете този модел, резултатът е абсолютно същият със или без блокови тагове. Блоковете имат достъп до променливи от външни диапазони. Това е просто начин да се направи така, че да може да се пренастройва за шаблона на детето:
Сега при визуализиране на шаблона на детето цикълът ще използва
блока, дефиниран в шаблона на детето child.Latte
, вместо блока,
дефиниран в базовия шаблон parent.Latte
; изпълненият шаблон ще бъде
еквивалентен на следния:
Ако обаче създадем нова променлива вътре в именуван блок или заменим стойността на съществуваща променлива, промяната ще бъде видима само вътре в блока:
Съдържанието на блока може да се променя с помощта на филтри. В следващия пример целият HTML е премахнат и е дадено заглавието:
Тагът може да се запише и като n:attribute:
Местни блокове
Всеки блок отменя съдържанието на родителския блок със същото име. С изключение на местните блокове. Те донякъде приличат на частните методи в класа. Можете да създадете шаблон, без да се притеснявате, че той ще бъде презаписан от втори шаблон поради съвпадащите имена на блоковете.
Блокове за печат {include}
Вижте също {include file}
За да отпечатате блок на определено място, използвайте маркера
{include blockname}
:
Можете също така да изведете блок от друг шаблон:
Производните блокове нямат достъп до променливите на активния контекст, освен ако блокът не е дефиниран в същия файл, в който е включен. Те обаче имат достъп до глобални променливи.
Можете да предавате променливи на блока по следния начин:
За име на блока можете да използвате променлива или друг израз в PHP. В
този случай добавете ключовата дума block
преди променливата,
така че по време на компилиране да се знае, че това е блок, а не шаблон за вмъкване, чието име също може да бъде в
променливата:
Блокът може да бъде отпечатан и вътре в себе си, което е полезно например при визуализиране на дървовидна структура:
Вместо {include menu, ...}
можете да напишете и {include this, ...}
,
където this
означава текущия блок.
Изходното съдържание може да се променя с помощта на филтри. В следващия пример целият HTML е премахнат и е вмъкнато заглавието:
Родителски блок
Ако трябва да визуализирате съдържанието на родителски блок от
родителски шаблон, операторът {include parent}
е полезен. Това е
полезно, ако искате да разширите съдържанието на родителския блок, а не
да го замените изцяло.
Определения {define}
Освен блокове в Latte има и „дефиниции“. Те могат да се сравнят с функциите в традиционните езици за програмиране. Те са полезни за повторно използване на фрагменти от шаблони, така че да не се повтарят.
Latte се опитва да опрости нещата, така че основно дефинициите са същите като блоковете и всичко, казано за блоковете, се отнася и за дефинициите. Те се различават от блоковете по това:
- те са затворени в тагове
{define}
- визуализират се само когато са вмъкнати чрез
{include}
- можете да задавате параметри за тях като за функциите в PHP
Представете си, че имате помощен шаблон с набор от дефиниции за това как да изготвяте HTML форми.
Аргументите на дадена дефиниция са винаги незадължителни със
стойност по подразбиране null
, освен ако не е посочена стойност по
подразбиране (тук 'text'
е стойността по подразбиране за
$type
). Типовете параметри също могат да бъдат декларирани:
{define input, string $name, ...}
.
Шаблонът с дефинициите се зарежда с помощта на {import}
. Самите дефиниции се визуализират по същия начин, както блоковете:
Дефинициите нямат достъп до променливите на активния контекст, но имат достъп до глобалните променливи.
Динамични имена на блокове
Latte позволява много гъвкаво именуване на блокове, тъй като името на
блока може да бъде всеки израз на PHP. В този пример са дефинирани три
блока с имена hi-Peter
, hi-John
и hi-Mary
:
Например, можем да заменим само един блок в шаблона на детето:
Така изходът ще изглежда по следния начин:
Проверка на съществуването на блока {ifset}
Вижте също {ifset $var}
Използвайте теста {ifset blockname}
, за да проверите дали даден блок
(или няколко блока) съществува в текущия контекст:
За име на блока можете да използвате променлива или друг израз в PHP. В
този случай добавете ключовата дума block
пред променливата, за да
стане ясно, че тя не е тази,
която се тества:
Съществуването на блокове се връща и от функцията hasBlock()
:
Съвети
Ето няколко съвета за работа с блокове:
- Последният блок от най-високо ниво не трябва да има затварящ таг (блокът завършва с края на документа). Това улеснява писането на шаблони за деца с един основен блок.
- За по-голяма прегледност можете по желание да дадете име на тага
{/block}
, например{/block footer}
. Името обаче трябва да съвпада с името на блока. В по-големи шаблони тази техника помага да се види кои блокови тагове са затворени. - Не можете да дефинирате директно няколко блокови тага с едно и също име в един шаблон. Но това може да се постигне чрез използване на динамични имена на блокове.
- Можете да използвате n:attributes, за да дефинирате
блокове като
<h1 n:block=title>Welcome to my awesome homepage</h1>
- Блоковете могат да се използват и без имена, само за да се прилагат филтри към изхода:
{block|strip} hello {/block}
Хоризонтална повторна употреба {import}
Хоризонталната повторна употреба е третият механизъм за повторна
употреба и наследяване в Latte. Той позволява зареждане на блокове от
други шаблони. Подобно е на създаването на файл с помощни функции в PHP и
последващото му зареждане с помощта на require
.
Въпреки че наследяването на оформлението на шаблона е една от най-мощните функции на Latte, то е ограничено до просто наследяване – един шаблон може да разшири само един друг шаблон. Хоризонталното повторно използване е начин за постигане на многократно наследяване.
Нека имаме набор от дефиниции на блокове:
Използвайки командата {import}
, импортирайте всички блокове и дефиниции, дефинирани в blocks.latte
, в друг шаблон:
Ако импортирате блоковете в родителския шаблон (т.е. използвате
{import}
в layout.latte
), блоковете ще бъдат достъпни и във всички
дъщерни шаблони, което е много удобно.
Шаблонът, който е предназначен да бъде импортиран (напр.
blocks.latte
), не трябва да разширява друг шаблон,
т.е. да използвате {layout}
. Той обаче може да импортира други
шаблони.
Тагът {import}
трябва да е първият таг на шаблона след {layout}
.
Името на шаблона може да бъде произволен израз на PHP:
Можете да използвате толкова изрази {import}
, колкото искате в
даден шаблон. Ако два импортирани шаблона дефинират един и същ блок,
печели първият. Най-голям приоритет обаче има основният шаблон, който
може да презапише всеки импортиран блок.
Съдържанието на презаписаните блокове може да бъде запазено чрез вмъкване на блока по същия начин, както при родителския блок:
В този пример {include parent}
правилно ще извика блока sidebar
от
шаблона blocks.latte
.
Наследяване на блокове {embed}
Наследяването на единици пренася идеята за наследяване на оформлението на нивото на части от съдържанието. Докато наследяването на оформлението работи със „скелети на документи“, които се анимират от подчинени шаблони, наследяването на единици ви позволява да създавате скелети за по-малки части от съдържанието и да ги използвате повторно навсякъде.
При наследяването на единици ключовият етикет е {embed}
. Той
съчетава поведението на {include}
и {layout}
. Той ви позволява да
включвате съдържание от друг шаблон или блок и по желание да предавате
променливи, както и {include}
. Той също така ви позволява да замените
всеки блок, дефиниран в рамките на включен шаблон, както и
{layout}
.
В примера ще използваме сгъваемия елемент акордеон. Нека разгледаме
скелета на елемента в шаблона collapsible.latte
:
Таговете {block}
дефинират два блока, които могат да попълват
подчинени шаблони. Да, както в случая с шаблона-родител в шаблона за
наследяване на оформлението. Можете да видите и променливата
$modifierClass
.
Нека използваме нашия елемент в шаблона. Тук се намира {embed}
.
Това е изключително мощен набор, който ни позволява да правим всичко:
да включваме съдържанието на шаблона на елемента, да добавяме
променливи към него и да добавяме персонализирани HTML блокове
към него:
Резултатът може да изглежда така:
Блоковете в таговете за вграждане образуват отделен слой, независим
от другите блокове. Затова те могат да имат същото име като блока извън
вграждането и не се влияят от него. С помощта на тага include в таговете {embed}
, можете да вмъкнете
блокове, създадени тук, блокове от шаблона за вграждане (които не
са локални), както и блокове от основния шаблон,
които са локални. Можете също така да импортирате
блокове от други файлове:
Вградените шаблони нямат достъп до активни контекстни променливи, но имат достъп до глобални променливи.
Не само шаблони, но и други блокове могат да бъдат вмъкнати с
{embed}
, така че предишният пример може да бъде написан по
следния начин
Ако подаваме израз на {embed}
и не е ясно дали става въпрос за блок
или име на файл, добавете ключовата дума block
или file
:
Примери за употреба
В Latte има различни видове наследяване и повторно използване на кода. Нека обобщим основните понятия за по-голяма яснота:
{include template}
Случай на употреба: Използване на header.latte
и footer.latte
вътре в layout.latte
.
header.latte
footer.latte
layout.latte
{layout}
Пример за използване: Разширение layout.latte
вътре в
homepage.latte
и about.latte
.
layout.latte
homepage.latte
about.latte
{import}
Приложение за потребителя: sidebar.latte
към single.product.latte
и
single.service.latte
.
sidebar.latte
single.product.latte
single.service.latte
{define}
Пример на потребителя: Функция, която получава някои променливи и извежда някои маркировки.
form.latte
profile.service.latte
{embed}
Пример на потребителя: Вграждане на pagination.latte
в
product.table.latte
и service.table.latte
.
pagination.latte
product.table.latte
service.table.latte