MACRO содержит различные средства, которые позволяют собирать конечные шаблоны из набора других шаблонов:
MACRO компилирует шаблоны только целиком! То есть сначала обрабатываются все теги, такие как {{include}}, {{wrap}}, {{into}}, {{apply}} , и только затем окончательно создается откомпилированный шаблон. Именно поэтому разбиение шаблона на составляющие в MACRO с точки зрения выполнения конечного шаблона ничего не стоит (лишь увеличивается время компиляции). Это дает нам возможность выносить в отдельные шаблоны все, что повторяется в нескольких файлах.
Цель данной страницы - показать способы «снижения дублирования» в MACRO-шаблонах, то есть как максимально эффективно использовать все возможности MACRO по композиции шаблонов.
Включение (include) одного шаблона в другой. Include в MACRO осуществляется посредством тега {{include}}. По-умолчанию, включаемый файл компилируется как обычный шаблон.
{{include file='header.phtml'}} [...content...] {{include file='footer.phtml'}}
Если вы используете MACRO совместно с пакетом VIEW, и в атрибуте file используется абсолютное значение (начинается с / или с c:/), тогда MACRO подключает шаблон по абсолютному пути. В противном случае - пытается найти шаблон через механизм подключения шаблонов.
Стоит также обратить внимание, что при включении шаблона включаемый шаблон должен быть сбалансированным с точки зрения MACRO-тегов. То есть если тег предусматривает закрывающий тег, например, тег {{list}} или {{pager}}, значит и закрываться он должен в том же файле.
Обворачивание (wrap) – это вставка текущего шаблона в определенное место другого шаблона.
С обворачиванием шаблонов связаны следующие термины:
Обворачивание производится при помощи тега {{wrap}}. Слот для вставки помечается в базовом шаблоне тегом {{slot}}.
Рассмотрим небольшой пример:
page.html – базовый шаблон
<html> <head> [...meta...] </head> <body> {{slot id='content'/}} </body> </html>
my_page.html – текущий шаблон
{{wrap with='page.html' into='content'}} [...content...] {{/wrap}}
В результате получим нечто:
<html> <head> [...meta...] </head> <body> [...content...] </body> </html>
Разберем подробнее, как работает тег {{wrap}}. {{wrap}} требует закрывающего тега. Обворачиваемой считается та часть текущего шаблона, что обрамлена в рамки тега {{wrap}}.
По-умолчанию {{wrap}} вставляет все свое содержимое в слот, указаный при помощи атрибута into.
Однако можно различные части текущего шаблона отправить в различные слоты базового шаблона. Для этого используется тег {{into}}.
Поясним это все на примере:
Допустим есть базовый шаблон страницы page.html:
<html> <body> {{slot id='content'/}} </body> </html>
Также шаблон дополнительного дизайна layout.html с двумя местами для вставки (как бы второй базовый шаблон):
<div id='header'>{{slot id='header'/}}</div> <div id='main'>{{slot id='main'/}}</div>
И теперь текущий шаблон display.html:
{{wrap with='page.html' into='content'}} {{wrap file='layout.html'}} {{into slot='header'}}My Header{{/into}} {{into slot='main'}}My Complex content{{/into}} {{/wrap}} {{/wrap}}
На выходе получим:
<html> <body> <div id='header'>My Header</div> <div id='main'>My Complex content</div> </body> </html>
Необходимо пояснить, как именно компилируется шаблон в данном случае. Сначала обрабатывается первый {{wrap}} и мы получаем на 1-м шаге компиляции следующий шаблон:
<html> <body> {{wrap with='layout.html'}} {{into slot='header'}}My Header{{/into}} {{into slot='main'}}My Complex content{{/into}} {{/wrap}} </body> </html>
Затем обрабатывается второй {{wrap}} и условно получается:
<html> <body> <!-- Дочерние {{into}} теги сначала ищут контейнеры вставки в этих рамках --> <div id='header'>{{slot id='header'/}}</div> <div id='main'>{{slot id='main'/}}</div> {{into slot='header'}}My Header{{/into}} {{into slot='main'}}My Complex content{{/into}} <!-- ...... --> </body> </html>
В результате работы тегов {{into}} получается конечный результат.
Если {{into}} тег находит вне {{wrap}} тега, тогда он пытается найти соответстувующий тег {{slot}} начиная с корня дерева компилируемого шаблона.
Представим, что вам необходимо вывести 2 списка элементов одинакомым образом, однако имеющим различные источники данных. Например, на первой странице раздела нам нужно вывести лучшие товары и остальные товары раздела.
Первое решение - это вынести повторяющуюся часть шаблона в отдельный файл и подключать его 2 раза при помощи тега {{include}}. Это хороший вариант, если вы собираетесь использовать этот выделенный шаблон несколько раз еще в других шаблонах.
Если же общая часть используется только в рамках одного шаблона, то этих целей целесообразно использовать комбинацию тега {{template}} и нескольких тегов {{apply}}.
Например:
{{template name="photo_tpl"}} <span class="date">{$item.ctime|date:"d.m.Y"}</span> <a href="/photo/item/{$item.id}" class="img"><img alt="{$item.title}" src="{$item.icon_file_url}"></a> <a href="/photo/item/{$item.id}" class="title">{$item.title}</a> <a href="#" class="author">{$item.member.nick}</a> <a href="{$item.thumbnail_file_url}" title="{$item.title}" class='preview'>предварительный просмотр</a> {{/template}} <h2>Лучшие фото рубрики {$#category.title}</h2> {{list using="$#best_photos" as="$photo"}} <ul id='best_photos_list'> {{list:item}} <li>{{apply template="photo_tpl" item="$photo"/}}</li> {{/list:item}} </ul> {{/list}} <h2>Все фото рубрики {$#category.title}</h2> {{list using="$#photos" as="$photo"}} <ul id='photos_list'> {{list:item}} <li>{{apply template="photo_tpl" item="$photo"/}}</li> {{/list:item}} </ul> {{/list}}
Сам тег {{template}} ничего не рендерит. Только вызовы {{apply}} вставляют часть этого кода в нужное место. Обратите внимание, что на уровне откомплированного шаблона {{template}} создает отдельный метод, а {{apply}} - это по сути вызов этого метода. Поэтому то, что находится в рамках {{template}} - это по сути отдельный локальный контекст и локальные переменные в нем будут не видны, и их нужно туда передавать, что и реализовано в приведенном примере.
Обсуждение