Изменения

Шаблонизатор VMX::Template/Из раннего: I.GC

703 байта добавлено, 12:42, 20 июня 2016
''Данный документ оставлен в живых по исключительно историческим причинам.'' Это один из первых скриптов, которые я написал на PHP - PHP — тот самый "Index«Index.Generate и Index.Compile"Compile», о котором говорится [[Шаблонизатор VMX::Template/Старая PHP-версия|тут]]. На этом работала моя первая-первая домашняя страничка на h11h15.ru.  Ну что тут сказать?* Я тогда не знал, что в базе данных бывают индексы и первичные ключи, и использовал её как INI-файл. * Любовь к зюкам-хрюкам началась давно и сразу.* Это ж надо было столько кода понаписать! Форматировать задолбался. Код:){{SVN|vitaphoto/archive/i.gc.2006-04-24}}
Написано 2006-04-24. <!-- старая ссылка: http://vmx.yourcmc.ru/filelist.php?file=135 -->
----- <pre> \----------------------/ == VMX index.php 1.06 /----------------------\</pre>==
index.php - php — php-скрипт, который строит HTML код (на самом деле - деле — вообще любой файл, но предназначен именно для генерации HTML-кода), основываясь на шаблоне и данных БД MySQL.
Зачем оно надо? Веб-дизайнер может создать ПУСТОЙ макет страницы, расставить управляющие коды и получить готовый к использованию шаблон. Далее к сайту создаётся БД (например, через gendbv2.php), и весь сайт работает сгенерированный через index.php.
Естественно, шаблонов может быть несколько - несколько — например, один для страницы с новостями, другой для страницы с файлами, третий ещё для чего-нибудь... нибудь… Несколько шаблонов вместе образуют тему. Темы располагаются в подпапке themes/ относительно папки с index.php. Каждая тема лежит в отдельной подпапке: themes/<имя_темы>
Названия всех таблиц в БД, относящихся к сайту, по умолчанию начинаются с Pages, за это отвечает переменная $PagesTable (см. config.php). Во всех таблицах должна присутствовать индексная колонка "Id"«Id». Других требований к таблицам НЕТ. При переходе в любую таблицу командой $$jmp к её имени в начало дописывается Pages (вернее, переменная $PagesTable).
Конфигурационные переменные $db, $dbhost, $dbuser, $dbpwd - dbpwd — отвечают за имя БД, хост, на котором расположен сервер MySQL, имя пользователя MySQL и пароль MySQL соответственно.
index.php следует вызывать так: "«<tt><nowiki>index.php?id=<ИНДЕКС_СТРАНИЦЫ_В_ТАБЛИЦЕ_СТРАНИЦ_БД>&t=<ШАБЛОН>&theme=<ТЕМА></nowiki></tt>"». Ни один из этих трёх параметров не является обязательным. По умолчанию id=1, theme=default, t=default, т.е шаблон по умолчанию - умолчанию — это "templates«templates/default/default"default».
Шаблон - Шаблон — любой текстовый файл, в который добавлены управляющие коды.
В самом начале обрабатываются все команды "«$$include$FILE" - FILE» — см.ниже.
Потом обрабатываются подстановки типа:
;<tt><nowiki><<i>></nowiki></tt> (i - i — число): подставит значение Id'а Id’а записи таблицы, обрабатываемой на уровне вложенности i (0 - 0 — весь файл, 1,2,... - … — циклы)
;<tt><<#>></tt>: подставит значение текущей обрабатываемой записи в таблице.
;<tt><<#STR>></tt>: выводится номер записи, обрабатываемой на текущем+длина(STR) уровне вложенности
;<tt><<#-STR>></tt>: выводится номер записи, обрабатываемой на текущем-1-длина(STR) уровне вложенности
;<tt><<##STR>></tt>: выведется <<«#STR>>STR»
;<tt><<%>></tt>: номер текущей итерации
;<tt><<@>></tt>: индекс последней вставленной в БД записи (используется функция mysql_insert_id())
Имя переменной - переменной — далее VAR - VAR — это одно из:
;просто строка: тогда это не переменная
:;<tt><nowiki>*{Inum}</nowiki></tt>: номер текущей итерации цикла, начиная с нуля
:;*<tt><nowiki>{amy_query_count}</nowiki></tt>: количество произведённых SQL запросов
;<tt><nowiki>[FieldName]</nowiki></tt>: тогда значение будет прочитано из поля FieldName текущей обрабатываемой записи. Эквивалентно [<<#>>\FieldName], где # -  — номер текущего уровня вложенности.
;<tt><nowiki>[Id\FieldName]</nowiki></tt>: тогда значение будет прочитано из поля FieldName записи с индексом Id текущей таблицы.
;<tt><nowiki>[#Special\FieldName]</nowiki></tt>: специальные значения. Вызывают SQL-запрос вида "«<tt><nowiki>SELECT Special(FieldName) FROM `TableName`</nowiki></tt>"».
Примеры:
;<tt>[#MAX\Id]</tt>: максимальное значение поля Id в текущей таблице
Если перед любым из этих выражений поставить \, то она преобразуется через mysql_escape_string. Если @, то как html_pbr (преобразование переводов строк в <tt><nowiki><br /></nowiki></tt>, а символов <tt>&<>"'</tt> -  — в HTML-entity). Если & -  — тогда преобразование заключается в удалении всех HTML тэгов кроме разрешённых в config.php. Если поставить \\, то это воспримется просто как символ \. Если @@ -  — то @. Если && -  — просто &.
Итак: вне команд $VAR$ -  — подстановка переменной. В командах - командах — смотрите отдельно :)
Команды (ставятся на отдельную строку):
;<tt>$$sql$QUERY</tt>: выполнить запрос QUERY. QUERY - QUERY — может содержать подстановки переменных.;<tt>$$qor$QUERY</tt>: выполнить запрос QUERY и обработать результат в цикле.;<tt>$$wor$table$where</tt>: частный случай предыдущего::<tt>SELECT * FROM `table` WHERE where</tt>:Значит - Значит — обработать в цикле все записи table, соответствующие WHERE-выражению where. where - where — это вся часть строки после $$wor$. Примечание: Если не хотите никуда переходить - переходить — напишите $$wor${table}$... Т.к глобальная переменная PHP table - table — это текущая таблица.:Примеры::;<tt>$$wor$1</tt>: обойти всю таблицу.:;<tt>$$wor$Id>=1 AND Id<=5</tt>: обойти записи с индексами от 1 до 5.:;<tt>$$wor$Id>=1 LIMIT 5</tt>: обход 5 записей, начиная с индексов больших 1. (см. 9 подсказку);<tt>$$for$table$VAR1$VAR2</tt>: Частный случай цикла wor. Обход Id>=VAR1 AND Id<VAR1+VAR2;<tt>$$filter$VAR1$VAR2</tt>: Цикл, выбирающий из текущего кэша записи, у которых значение колонки VAR1 равно VAR2;<tt>$$whileXX$VAR1$VAR2</tt>: Цикл повторяющий своё тело до тех пор, пока VAR1 XX VAR2 истинно;<tt>$$cache$WHERE</tt>: Кэширование текущей записи или всех записей, соответствующих WHERE;<tt>$$cache</tt>: Кэширование текущей записи;<tt>$$cacheassign$LEVEL</tt>: присвоить текущий кэш равным кэшу уровня LEVEL ;<tt>$$cleancache</tt>: Очистка кэша;<tt>$$exit</tt>: Останов или выход из итерации цикла;<tt>$$break</tt>: Выход из цикла;<tt>$$block</tt>: Начало блока (например, if'a)
:Пример:
:<tt>$$block</tt>:<tt>$$if<?$VAR1$VAR2</tt>:<tt>...</tt>:<tt>$$/</tt>
:- это if (VAR1 < VAR2) { ... }
;<tt>$$/</tt>: конец блока или тела цикла;<tt>$$ifXX$VAR1$VAR2</tt>: оператор условного выхода - проверить VAR1 XX VAR2. Если ложь, выйти. Для цикла "выйти" значит "перейти к следующей записи таблицы". Внимание! Не используйте это в циклах - будет неоптимально.;<tt>$$include$FILE</tt>: прямое включение шаблона. В FILE никаких переменных! Кроме того, эта команда ДОЛЖНА стоять на отдельной строке.;<tt>$$php$VAR</tt>: включение и выполнение php-кода из файла VAR.;<tt>$$chg$VAR</tt>: переключение на обработку записи под индексом VAR. ВНИМАНИЕ! О кэшировании новой записи она не заботится.;<tt>$$wtime</tt>: вывести текущее время выполнения.
Вниманию оптимизаторов! Следующие три команды очищают кэш.
;<tt>$$jmp$VAR</tt>: перейти в таблицу с именем VAR.;<tt>$$ret</tt>: вернуться на предыдущую таблицу (история хранится);<tt>$$aret</tt>: вернуться на главную таблицу и очистить историю переходов
Поддерживается вложенная буферизация вывода в 3 режимах - добавление в буфер справа (A+B = AB), слева (A+B = BA), или без буферизации. По умолчанию буферизация 1 уровня справа.
;$$bufstartR: начать новый уровень буферизации справа
;$$bufstartL: начать новый уровень буферизации слева
;$$bufchgR: изменить метод буферизации на буферизацию справа
;$$bufchgL: изменить метод буферизации на буферизацию слева
;$$bufclear: очистить буфер текущего уровня наффиК
;$$bufflush: сбросить буфер текущего уровня в буфер предыдущего уровня
;$$bufstop: закончить текущий уровень буферизации и сбросить буфер в предыдущий
;$$bufsave$name: сохранить буфер под именем name (обращаться потом как ${{name}}$)
;$$save$name$value: сохранить value как name; для index.php $$define$name$value делает то же самое.
compile.php - специфичные команды ;<tt>$$bufstartR</tt>: начать новый уровень буферизации справа;<tt>$$bufstartL</tt>: начать новый уровень буферизации слева;<tt>$$bufchgR</tt>: изменить метод буферизации на буферизацию справа;<tt>$$bufchgL</tt>: изменить метод буферизации на буферизацию слева;<tt>$$bufclear</tt>: очистить буфер текущего уровня наффиК;<tt>$$bufflush</tt>: сбросить буфер текущего уровня в буфер предыдущего уровня;<tt>$$bufstop</tt>: закончить текущий уровень буферизации и подстановкисбросить буфер в предыдущий;<tt>$$bufsave$name</tt>:сохранить буфер под именем name (обращаться потом как ${{name}}$);<tt>$$save$name$value</tt>: сохранить value как name; для index.php $$define$name$value делает то же самое.
<tt>compile.php</tt> - специфичные команды и подстановки: ;<tt>$$define$name$value</tt>: сохранить value как name НА ВРЕМЯ КОМПИЛЯЦИИ. То есть, разница между $$save и $$define при компиляции такая: если написать $$save$name$value - в php-код запишется строка типа $saved_buffers [name] = value; а при использовании define значение будет подставляться прямо в то место, где используется. При этом все подстановки внутри него всё равно работают.;<tt>$$phpverbatim$filename.php</tt>: прямое включение в выходной php-код отрезка файла filename.php начиная с первого <?php и кончая первым ?>;<tt>$$phpfunc$filename.php</tt>: создастся функция с телом, равным отрезку файла filename.php начиная с первого <?php и кончая первым ?>, и тут же и вызовется;<tt>подстановка {(VarName)}</tt>: это как раз подстановка define'овdefine’ов.
Логические операции (XX в $$if и $$while):
;==: численное/лексикографическое сравнение на "равно".
;!=: численное/лексикографическое сравнение на "не равно".
;>=: численное/лексикографическое сравнение на "больше «больше или равно"равно».;>: численное/лексикографическое сравнение на "больше"«больше».;?: проверка, задана ли глобальная переменная PHP VAR1 - VAR1 — true если задана и непуста как строка;!?: отрицание "«?"»
Причём, в именах полей/идентификаторах также можно использовать <tt><nowiki><<i>></nowiki></tt> т.к всегда и сначала подставляются <tt><nowiki><<i>></nowiki></tt>.
Для оптимизации работы с БД записи кэшируются. Вначале, при запуске скрипта кэшируется не больше одной записи с Id равным $recid. Однако потом, в циклах, кэшируется сразу много записей. А именно - именно — все, подходящие под границы цикла. В принципе, это может создать проблемы с памятью при обработке действительно крупных объёмов данных. Но на практике всё будет нормально.
Далее, compile.php. Как и видно из названия - названия — этот скрипт компилирует шаблоны. То есть, создаёт PHP скрипты, делающие то же самое, что и index.php при интерпретации шаблонов. Вызывать его следует так же, как и index.php: <tt><nowiki>/compile.php[?t=TEMPLATE][&theme=THEME]</nowiki></tt>. При этом выход запишется в файл THEME_TEMPLATE.php в ту же папку, где лежит сам compile.php. Шаблоны он берёт оттуда же, откуда и index.php. При работе compile.php меняет все вхождения <tt><nowiki>/index.php[?t=...][&theme=...]</nowiki></tt> на вызов соответствующего откомпилированного скрипта.
Кроме того, вы можете указать дополнительные опции компилятора шаблонов:
;&no_cache_when_reading: не обновлять кэш, если в нём нету переменной - переменной — немного оптимизирует скрипт по времени работы. Не обновлять - обновлять — то есть не записывать код, производящий обновление кэша.;&generate_comments: генерировать комментарии - комментарии — записывать каждый кусок файла в комментарии перед командами, ему соответствующими.;&default_theme=DEF: переименовать тему по умолчанию в DEF, если DEF пусто - пусто — тогда имена файлов будут просто TNAME.php.
;&default_t=DEF: переименовать шаблон по умолчанию в DEF.
:Переименование влияет на имена подставляемых вместо /index.php[?t=...][&theme=...] скриптов и на имя выходного скрипта.
Также для удобства создан скрипт compileui.php - php — пользовательский интерфейс компилятора. Заполните поля ввода и нажмите кнопку "компилировать тему" - «компилировать тему» — после этого все шаблоны темы с названием, заданным в поле "тема"«тема», кроме шаблонов, лежащих в файлах с расширениями, откомпилируются и будут помещены в ту же папку, где лежит compileui.php. compile.php для работы через compileui.php должен находиться в корневой папке сервера.
* Поле "тема" «тема» задаёт компилируемую тему.* Поле "тема «тема default=" - аналог параметра компилятора &default_theme=DEF.
* Поле "шаблон default=" - аналог параметра компилятора &default_t=DEF.
* Флажок "Управляю кэшем вручную и корректно" - корректно» — аналог опции компилятора &no_cache_when_reading.* Флажок "Генерировать «Генерировать комментарии к коду" - коду» — аналог опции компилятора &generate_comments.
<pre> \-------------------------/ == Подсказки разработчикам /-------------------------\</pre>==
# Во-первых, в принципе, скрипт не ориентирован на ввод информации в БД, хотя он вполне может осуществляться - осуществляться — через команду $$sql, формы и глобальные переменные PHP. Все переменные запроса импортируются с req_ перед названием. То есть, если у вас на странице есть что-то вроде <tt><nowiki><input type="text" name="helloworld" maxlength=256></nowiki></tt> -  — то после отправки формы текст из этого поля ввода появится как переменная ${req_helloworld}$. Соответственно, вы можете использовать её в SQL запросе.# В ту же тему: если ваш движок должен поддерживать некую конфигурацию через config.php - php — допишите в него между "«<?php" и "?>" » строки вида "«$YOUR_VAR_NAME = YOUR_VAR_VALUE;" » и далее сможете использовать их как ${YOUR_VAR_NAME}$.# Чтобы включить форму аутентификации - аутентификации — нужно написать ОТДЕЛЬНО два php-скрипта - скрипта — один для вывода формы или приветствия, а другой для обработки команд аутетификации. Связано это с тем, что протокол HTTP не позволяет передавать HTTP Cookies иначе, чем как ДО НАЧАЛА любого вывода скрипта. То есть - есть — скрипт-обработчик команд "вход" «вход» и "выход" «выход» должен быть включён в САМОМ начале шаблона - шаблона — на первой строке. Так же и с любыми скриптами, работающими с HTTP Cookies. Скрипт, выводящий форму или приветствие, вы можете размещать где угодно. '''UPD: ЛИБО (проще) в начале включаете буферизацию справа ($$buf+r), и выводите страницу.'''# Старайтесь оптимизировать работу с базой данных: именно MySQL является узким местом в производительности. В принципе, для этого много умения не надо :) но, например: допустим, есть таблица с категориями файлов, которые образуют иерархическую структуру. Категорий файлов, как правило, немного, и их можно кэшировать прямо все, потому что иерархический обход с использованием while - while — штука, которая без ручного кэширования кушать запросы будет только так. Соответственно, перед while переходим в требуемую таблицу, кэшируем все её записи - записи — $$cache$1, и дальше начинаем while.# Цикл идентифицирует итерации по колонке Id. Так что если её в строках результата не будет, она, хы, доопределится :) причём - причём — отрицательными значениями. Чтобы было ясно, что это 'несуществующие' индексы.# Т.к $$sql требуется обычно для SQL-выбора из нескольких таблиц, то имейте ввиду, что в теле цикла, мягко говоря, не рекомендуется использовать записи с индексами кроме выбранных самим запросом - запросом — если выбор шёл из одной таблицы они, при отсутствии в кэше, подгрузятся, а здесь "угадать" «угадать» таблицу скрипт не сможет.# Не используйте в циклах операторы условного выхода - выхода — неоптимально.# При включении PHP-скрипта командой $$php скрипт будет "по умолчанию" «по умолчанию» видеть следующие 3 глобальные переменные:#* $link - link — MySQL соединение с БД;#* $result - result — MySQL результат запроса;#* $table - table — имя текущей таблица;
#: Осторожно обращайтесь с этими переменными во включаемых php-скриптах. При их повреждении страница, скорее всего, отобразится некорректно.
# "«$$wor$Id>=1 AND Id<=5" и "$$wor$Id>=1 LIMIT 5" - 5» — это разные вещи. Потому что если, например, индексов >=1 и <=5 нету, а начинаются они, например, лишь с 7, то первая команда не обойдёт ничего, а вторая обойдёт <= 5 записей, начиная с 7-ой.
# Вообще говоря - $$include$FILE - это не команда. Собственно интерпретатор даже не видит такие команды - они обрабатываются до него и прозрачно.
<pre> \---------/ == Примеры /---------\</pre>==
Обход таблицы вверх по иерархии. В таблице нам важны поля "name" - имя и "parent" - родительская запись.
Выводит типа "КОРЕНЬ >> СЫН >> СЫН >> ... >> СЫН >> ТЕКУЩИЙ ЭЛЕМЕНТ"
<pre>
</pre>
[[Категория:РазработкаАрхив]]
[[Категория:Перенесено с vmx.yourcmc.ru]]