Pull to refresh

Иной — PHPTAL

Reading time7 min
Views1.7K
Для описания этого очень мощного и одновременно лаконичного шаблонизатора просто скопирую текст из мана
«PHPTAL is an implementation of the excellent Zope Page Template (ZPT) system for PHP. PHPTAL supports TAL, METAL, I18N namespaces» и «PHPTALES is the equivalent of TALES, the Template Attribute Language Expression Syntax. It defines how XML attribute values are handled»

Предлагается по LGPL лицензии тут http://phptal.org/.

Я делаю шаблоны на PHPTAL уже около года и считаю его «феерическим» :). В коде есть пара моих патчей, поэтому я знаю тему изнутри.

Далее я сделаю обзорную статью из которой вы точно поймете что я не писатель и почему всячески противился просьбам хабражителей «раскрыть тему» ну и надеюсь хоть чуть-чуть популяризирую данный шедевр.


XML-синтаксис



Шаблоны TAL, и PHPTAL соответственно тоже, это XML документы, причем жестокие и настоящие а не «там где угловые скобочки».
Тут вам и сущности и CDATA-секции и, не поверите, XML-декларация.

Чем это хорошо?
Это дисциплинирует — у вас никогда не останется не закрытых тегов из-за которых «вдруг» поедет верстка, шаблонизатор просто не пропустит такое безобразие.
Наверное нет редактора кода не понимающего XML формат.
Ваш верстальщик не школьник.

Чем это плохо?
Ваш верстальщик не школьник, да я помню что это было в плюсах, но теперь за 10 баксов вам табличками в фронтпейдже не сверстают
Реализация IE хаков может выводить из себя (в конце один из примеров)
Inline-JS лучше оформлять как CDATA секции, ну или делать «по взрослому» в отдельных js файлах.
Кое-кому прийдется почитать книгу про XML, не уверен что это плохо.

Атрибуты



Вся мощь TAL скрыта в атрибутах, в спецификации описать ровно 1 (один) элемент, и тот, как сказано в спеке «является синтаксическим сахаром», и без него можно вполне обойтись. Поэтому говорим TAL имеем в виду атрибуты.

Чем это хорошо — ровно всем, когда Вы получаете от верстальщика XHTML верстку она уже является шаблоном TAL, дальше будут только его итеративно «натягивать», именно в TAL «натягивать шаблон» очень точно характеризует процесс.

В упомянутой спеке на PHPTAL описано аж 18 служебных атрибутов, из которых добрую половину Вы никогда не будуте использовать.
Далее очень кратко пройдусь по действительно важным и используемым — описания буду давать кодом:

tal:define, tal:content


  <div tal:define="global title obj/getTitle; content obj/getContent">
    <div class="post_title" tal:content="title" >Lorem ipsum</div>
    <div class="post_content" tal:content="content" >Lorem ipsum</div>
  </div>


Обычные константы имеют область видимости ограниченную тегом в котором они определены, эта фича походу из xslt и позволяет избежать пересечения по именам.
Глобальные константы действуют на весь поток обработки шаблона, я пишу поток а не шаблон поскольку шаблоны могут быть наследуемыми и тогда при обработке одного, на самом деле обрабатывается цепочка шаблонов.
Пример когда глобальные константы сильно «доставляют» — в конце топика.

tal:condition, tal:repeat, tal:attributes, i18n:translate


  <div tal:repeat="post posts" tal:attributes="class php:repeat.post.odd ? 'odd' : NULL">
    <div class="post_title" tal:content="post/getTitle" >Lorem ipsum</div>
    <div class="post_content" tal:content="post/getContent" >Lorem ipsum</div>

    <a class="post_cut" tal:condition="post/hasMore" i18n:translate="">Read more</a>
  </div>


Тут список топиков с опуиональными ссылками на «more» и зеброй.
Тема зебры раскрыта в официальном мане phptal.org/manual/ru/split/tal-attributes.html
При полной обвязке шаблонизатора, в данном шаблоне текст «Read more» будет переводится транслейтором (gettext по умолчанию)

metal:define-macro, metal:use-macro, metal:define-slot, metal:fill-slot


Эти 4 атрибута реализуют наследование шаблонов, далее работаем c home.html шаблоном, который наследует общий для всех базовый layout:

home.html
<?xml version="1.0"?>
  <tal:block metal:fill-slot="custom-js" >
    <script rel="stylesheet" src="/mootools-1.2-fx.js" type="text/javascript" />
  </tal:block>


  <tal:block metal:fill-slot="custom-css"  >
    <style type="text/css" media="all">
      @import url(<tal:block tal:content="/main.css" />);
    </style>
  </tal:block>

  <tal:block metal:use-macro="layout/page" >
    <body metal:fill-slot="body" tal:define="global title post/getTitle">
      <div tal:content="post/getContent" >Post content text</div>
    </body>
  </tal:block>


layout.html
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"  “http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html metal:define-macro="page" xmlns="http://www.w3.org/1999/xhtml">

  <head >
    <title tal:content="title | default">PHPTAL global title example</title>
    
    <tal:block metal:define-slot="meta" >
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
      <meta name="generator" content="velocity framework" tal:attributes="content generator | default" />
      <meta name="description" tal:condition="exists: description" content="${description}" /> 
      <meta name="keywords" tal:condition="exists: keywords"  content="${keywords}" />
    </tal:block>

    <script rel="stylesheet" src="/mootools-1.2-core.js" type="text/javascript" />

    <tal:block metal:define-slot="custom-js" />

    <style type="text/css" media="all">
      @import url(<tal:block tal:content="/main.css" />);
    </style>

    <tal:block metal:define-slot="custom-css" />
	    
  </head>
  
  <body metal:define-slot="body">Lorem ipsum</body>
</html>


Еще


Описанных 10 атрибутов достаточно для начала работы, остальные 8 хорошо описаны в мане

Тейлы



Как Вы могли заметить выше, выражения записываются в спец-формате, общий формат выражения:

prefix:выражение, если префикс не определен он считается равным «path»

В PHPTAL определены 5 типов выражений (path, php, string, not, exists), в оригинальном TAL php заменяется на python.
Каждый тип тейлов, а именно так именуются выражения, опеределяет формат, все хорошо описано в мане, остановлюсь только на базовом path.
Тейл path сделан очень похожим на XPath синтаксис, и знакомым с ним он будет очень удобен, так выражение:

obj/getObject2/path эквивалентно $obj->getObject2()->path;.

Анализатор path тейлов автоматически пытается вызывать соответствующие методы, члены и ключи массивов в порядке приоритетности из мана.

PHPTAL предумасматривает что разработчик будет дописывать сам нужные ему тейлы, тем самым расширяя фукционал.

Приемы и примеры



Глобальные константы


Глобальные константы бывают очень удобны, наиболее характерный пример – заголовок страницы. Теперь вы можете определять его в любом месте.

layout.html

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"  “http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html metal:define-macro="page" xmlns="http://www.w3.org/1999/xhtml">

  <head >
    <title tal:content="title | default">PHPTAL global title example</title>
    
    <tal:block metal:define-slot="meta" >
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
      <meta name="generator" content="velocity framework" tal:attributes="content generator | default" />
      <meta name="description" tal:condition="exists: description" content="${description}" /> 
      <meta name="keywords" tal:condition="exists: keywords"  content="${keywords}" />
    </tal:block>
	    
  </head>
  
  <body metal:define-slot="body">
</html>


home.html
<?xml version="1.0"?>

<tal:block metal:use-macro="layout/page" >
  <body metal:fill-slot="body" tal:define="global title post/getTitle">
    Page body
  </body>
</tal:block>


В указанном примере именно home.html шаблон используется для вывода, а давно написанный layout.html используется для однообразного обрамления, но даже в таком случае вы можете им управлять, в частности динамически выводить заголовок, например по названию поста блога из БД

Наследуемый вывод подключаемых ресурсов


Данный пример несколько перекликается с предыдущим но реализован иначе, допустим на нужно иметь возможность в наследущем шаблоне добавлять ресурсы (css js в head секцию лайоута):

layout.html

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"  “http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html metal:define-macro="page" xmlns="http://www.w3.org/1999/xhtml">

  <head >
    <script rel="stylesheet" src="/mootools-1.2-core.js" type="text/javascript" />

    <tal:block metal:define-slot="custom-js" />

    <style type="text/css" media="all">
      @import url(<tal:block tal:content="/main.css" />);
    </style>
    <tal:block metal:define-slot="custom-css" />
	    
  </head>
  
  <body metal:define-slot="body">
</html>


home.html
<?xml version="1.0"?>

<tal:block metal:use-macro="layout/page" >
  <tal:block metal:fill-slot="custom-js" >
    <script rel="stylesheet" src="/mootools-1.2-fx.js" type="text/javascript" />
  </tal:block>


  <tal:block metal:fill-slot="custom-css"  >
    <style type="text/css" media="all">
      @import url(<tal:block tal:content="/main.css" />);
    </style>
  </tal:block>

  <body metal:fill-slot="body" >
    Page body
  </body>
</tal:block>


Inline JS


<script type="text/javascript">
  //<![CDATA[
    var $var = ${json:var};
    // поскольку это CDATA можно юзать угловую скобку
    if ($var < 1) {
      // bla....bla
    }
  //]]>
</script>


Тут пример как писать JS не опасаясь служебных символов.
json: это мой самописный тейл который мапит переменную в JS код :)

Документация


Не всегда удобно пользоваться online версией. Вместе с исходниками шаблонизатора поставляется переведенная процентов на 50 docbook книга, все что вам останется – переконвертить ее в удобный формат. Используя инструменты доступные тут http://docbook.sourceforge.net/ можно получить даже chm, а при определенной сноровке и свободном времени и pdf.

Производительность


PHPTAL, как и смарти и многие другие, генерирует PHP-runtime код и работает уже с ним, код очень качественный и не избыточный за счет этого скорость очень и очень хорошая —
http://fabien.potencier.org/article/34/templating-engines-in-php
Tags:
Hubs:
Total votes 15: ↑10 and ↓5+5
Comments39

Articles