TTemplate - описание класса
12.02.2009TTemplate - это класс, который непосредственно генерирует html страницы, используя шаблоны темы. Чтобы понять, как работает TTemplate надо знать, как устроены шаблоны (темы) в блоголёте, а шаблоны в блоголёте устроены очень просто: это самый обычный html, без каких либо особых требований. TTemplate загружает файл шаблона и его обрабатывает, выдавая на выходе уже готовую html страницу. Обработка шаблона сводится к простому действию - текст шаблона принимается как будто это строка (string) в php, таким образом все переменные в строке заменяются их значениями. Приведем пример - это одна строка из каждого файла шаблона блоголёта:
<title>$Template->title</title>
В результате тег title в html странице будет иметь значение свойства title объекта $Template. Дальше начинается самое интересное. В блоголете свойства объектов могут вызывать соответствующие методы, а конкретно для этого случая будет вызван метод Gettitle(). Это простой трюк, чтобы в обычный html текст внедрить вызов php функций при этом никак не нарушая читабельность исходного html, дав тем самым вэбмастеру свободу в создании тем для блоголёта. Не нужно более продираться сквозь нагромождения конструкций вида:
<title><?php echo ?$Template->title; ?></title>
Принятие такой парадигмы шаблонов в блоголёте является реализацией концепции разделения кода и представлений. То есть удалось красиво разделить исполняемый php код и html, сделав их друг от друга независимыми.
Если пойти дальше по цепочке и посмотреть исходный код метода Gettitle, то мы увидим следующее:
public function Gettitle() {
global $Options;
$result = '';
if ($this->DataObject->PropExists('title')) {
$result = $this->DataObject->title;
}
if (empty($result)) {
$result = $Options->name;
} else {
$result = "$result | $Options->name";
}
return $result;
}
Мы увидим в этом участке кода использование объекта DataObject - это как раз тот самый объект, который был найден по урлу в классе TUrlmap и передан в TTemplate для генерации html страницы.
Одним из центральных свойств в TTemplate является content. Как правило шаблон устроен достаточно стандартно - html заголовок, меню, контент, сайтбар, подвал. И как правило html страницы отличаются друг от друга контентом - его центральной частью, имея все остальное одинаковое - шапку, меню, сайтбар и подвал. Поэтому одна из основных концепций класса TTemplate является возможность предоставить объекту DataObject генерировать контент, который будет вставлен в получившийся html. Объект DataObject может отдавать контент несколькими способами - посмотрим исходный код метода Getcontent в классе TTemplate:
public function Getcontent() {
$result = $this->BeforeContent();
if (empty($result)) $result = '';
if (method_exists($this->DataObject, 'GetTemplateContent')) {
$result .= $this->DataObject->GetTemplateContent();
} elseif ($this->DataObject->PropExists('content')) {
$result .= $this->DataObject->content;
}
$result .= $this->AfterContent();
return $result;
}
Переводя код на человеческий язык - если можно , то вызываем метод GetTemplateContent, иначе пытаемся получить значение свойства content объекта DataObject. На уровне класса TTemplate совсем не важно, как и откуда объект получит контент. В результате мы имеем унифицированный подход к получению контента, например класс THomepage (главная страница) возвращает текст сгенерированный из анонсов записей. Забегая вперед можно раскрыть еще один секрет блоголёта - DataObject для отдачи контента может и использует тот же самый механизм генерации html на основе других файлов шаблона, например записи используют шаблон из файла post.tml текущей темы. Главным файлом шаблона является файл index.tml. Таким образом мы получаем вложенную в друг друга обработку файлов шаблона.
Получается простая иерархия файлов шаблонов: на верхнем уровне файл index.tml, в котором находится макет всей html страницы. На следующем уровне уже идут шаблоны анонса postexcerpt.tml, записи post.tml, страницы меню menuitem.tml. На этом стандартные файлы шаблонов заканчиваются.. Нет никаких проблем, чтобы каждая запись имела свой индивидуальный шаблон.
О виджетах и дополнительных тегах, будет рассказано отдельно.
← Ранее Обновление блоголёта
Позже Темы или шаблоны в блоголёте →
Комментарии (13) на запись “TTemplate - описание класса”
Оставить комментарий
Решений, как всегда, может быть несколько, по крайней мере создавать свой класс от ttemplate - это экстремизм.
1. Если хочется добавить собственные теги в ttemplate, то в текущей версии есть методы для добавления/удаление тегов: AddTag, DeleteTagg. Но этот путь требует редакции темы, чтобы добавить в шаблон темы новые теги
public function getexcerpt() {
return "Перед анонсом" . $this->data['excerpt'];
}
и тогда у каждого анонса будет впереди текст "Перед анонсом".
С другой сстороны это несколько плохой путь, потому что придется править исходник, а не в виде плагина. Можно это сделать и в виде плагина - создать свой класс потомок от tpost с этим методом и обязательным методом instance, но я сейчас с трудом могу сказать, каким образом можно заменить стандартныйкласс tpost на свой собственный - надо глядет исходники, и нет уверености, что в старой версии это получится
Наиболее предпочтительным вариантом выглядит второй-третий, поскольку вариант просто новых меток не прокатит - нужно вмешаться или в момент получения данных, или в момент их форматирования. Так что сейчас лажу по коду, возможно обойдется переделкой/дополнением THomepage.
И в связи с этим вопросы - сильно ли придется переделывать такое решение при переходе на следующую версию, и когда (ну ооочень примерно) ее ждать?
И заинтересованы ли вы сами в механизмах для создания журнальных тем /раздичное форматирование постов в списке, вывод записей по категориям, поле у категорий и-или постов "выводить на главной", прилепленные посты/?
Что касается тегов в ttemplate - остается по прежнему, только в новой версии появился вспомогатльный класс с методами add, delete и т.д. для управления. Если редактировать thomepage - то да, но лучше наверно посмотреть на плагин homepageinvert в качестве примера. И если возможно, то это будет даже наиболее оптимальный вариант. С другой сстороны мне больше нравится с наследником от tpost, но для этого мне надо будет добавить новое свойство в tclassess - remap, для переопределения классов. Хорошо, что ты задал вопрос - вроде как уже давно сделал список стандартных классов, чтобы можнобыло одним движением заменить существующий класс на свой собственный без поломки работоспособности и потом обратно вернуть как было.
Если есть возможность сделать свой класс вместо thomepage - то лучше его сделать.
Про обратную совместимость - скорее всего будет, но сейчас уже мне сложно об этом говорить, так как изменений накопилось очень много, но более чем возможна совмесимость, скорее всего с неболшими поправками.
Я заинтересован в любых нововведениях, и если необходимо, то поправлю для новых фич ядро
Что я на данный момент понял скажем так теоретически:
мне нужн поправить или добавить (еще не решил что лучше) некоторые методы из Thomepage (GetItems), TPosts (GetPublishedRange) - это если я решу в каком-то проекте делать разбивку по категориям, пока мне этого не надо - чтобы они принимали листинг категорий для выборки из $Options и реагировали на флаг приклейки, если он будет.
Для вывода же разноформатного надо модифицировать TTemplatePost->PrintPosts
И конечно если такие вещи можно будет делать перекрытием методов через классы-потомки - это будет очень удобно.
На плагин посмотрю.
Кстати в printpost нашел имхо неоптимальный фрагмент -
foreach($Items as $id) {
$GLOBALS['post'] = &TPost::Instance($id);
$Result .= $Template->ParseFile('postexcerpt.tml');
}
Или результат ParseFile('postexcerpt.tml') кешируется где-то? А то совершенно лишние ИО получаются на каждый пост.
Отвечаю в обратном порядке, обратная совместимость будет - во время разработки новой версии писал паралельно скрипт перехода, но изменения стали накапливаться и стало уже сложно править и скрипт перехода. После выхода версии, будет также сделан скрипт перехода - например blogolet.ru я однозначно переведу на новую версию, правда после ее стабилизации.
Файлы в старой версии кешируются - файлл читается только один раз при его первом обращении, как впрочем и любой файл темы. В новой версии вообще ничего читаться не будет, ну то есть будет один раз при смене темы парсится index.tml, а для управления шаблонами внутри темы введен новый класс ttheme, также осуществляется полный отказ от eval в пользу регэкспов.
Сейчас поправил управление классами, поэтому самый лучший вариантбыл бы через наследование от tpost. Но может быть следует замеменить шаблон самого анонса (что в старой версии было в postexcerpt.tml)?
Я просто до конца еще не осознаю решаемаю задачу, чтобы придумать правильное решение (правильное в смысле теоритически грамотное, а по простому наиболее простое и понятное большинству).
Сможешь ли сформулировать задачу таким образом, как это ты себе представляешь? Без привязки к блоголёту?
Собственно задачи 2:
1 - под конкретный проект, под текущую версию - буду делать на следующей неделе. Блог со статьями и двумя фото-категориями. Соответственно на главной выводятся тумбнейлы из этих двух категорий и анонсы последних статей.
Я сделаю через аналогию с плагином - отфильтрую посты по категориям в потомке thomepage. Может сделаю извлечение тумбнейлов отфильтровав дополнительно result, может даже и обойдусь - проект чисто личный.
Что там обычно характерно :
Первый и последующие посты на главной странице отличаются по оформлению - длинной выдержки, размером иллюстрации. Могут быть сгруппированы по категориям. На главную попадает только часть постов/категорий. Соответственно нужны фильтры по постам/категориям и механизм извлечения-ресайза-кроппинга картинок из текста при их наличии. На custom fields для картинок в вордпрессе пользователи плюются - и правильно делают. ИМХО это можно реализовать просто как сайтбар + специальные виджеты + возможно запрет на вывод стандартных анонсов. Также обычно выделяются несколько первых статей (или одна) на страницах категорий - при таком раскладе лайт режим в них смысла не имеет, особенно если хоумпейдж - одностраничный. Есть зачастую виджет - крутилка прилепленных постов, но это уже так, глазурь.
Вот характерный пример коммерческой темы такого плана (для демки надо нажать на картинку справа) http://www.woothemes.com/2009/09/daily-edition/
Ну и желание собственно - чтобы для таких фич была поддержка в ядре или стандартных плагинах. В плагинах возможно и лучше, поскольку за фильтрацию в БД версии может и не придется, а вот за группировку по категориям - явно придется платить скоростью и ресурсами.
Надеюсь сформулировал понятно :) Повторюсь по списку: фильтры по категория/постам, группировка по категориям, возможно с разными шаблонами выдержек для разных категорий, извлечение/авторесайз тумбнейлов, разные шаблоны выдержек для первого/последующих, а в идеале для любого по порядку на странице (в категории при группировке по категориям) поста. Что обеспечивает большое конкурентное превосходство над вордпрессом, где для этого надо возится с наладкой сложных тем и/или платить заметные деньги. :))
Далеко не все понял, вот что до меня дошло - прикрутить автоматическое создание скриншотов картинок для анонсов. Задача уже поставлена, и даже расширена до идеи создания мултимедийного сервеса, где бы автоматом делались скриншоты не только картинок, но и звук (wav,mp3), видио. Для видио еще конвертатор во флеш с прикручиванием кода плейера в пост из всех популярных форматов + возможно спецхостинг для видео.
Про остальное - не совсем понятна причина затруднений. Если нужна главная спецстраница, то стандартный класс просто выкидывается - он просто связан с одним адресом "/" и все, вместо этого вешается любой класс, например свой собственный (в обновленной идеологии с поддержкой интерфейса ITemplate для соблюдения требований), и творится там все, что угодно, например особая выборка по категориям, особые шаблоны анонсов и всего остального.
Структура блоголёта такова, что однажды созданный (привязанный) адрес не закрплен навечно за одним классом. После создания собственного класса для главной, единственным недостатком будет не работоспособностьв админке ннастройки/главная, которая управляет настройками главной.
Можно было бы сделать вообще весь движок как набор плагинов для каждого чиха, но это только бы сбивало с толку, хотя по своей сути блоголёт как раз и состоит из плагинов. Есть несколько базовых классов для управления (options, urlmap, classes, template, theme - в новой), вокруг которых все вертится, а все остальное прикрученные фичи. Например ппонадобился openid - был написан спецкласс для обработки адреса /openid/ вот и вся история
Во многих CMS стандартом для постов и категорий является флажок "публиковать на главной". Делать для этого свою таблицу по-моему чересчур.