webew
Войти » Регистрация
 
PHP
HTML

Легкий шаблонизатор на PHP

13 мая 2011, 17:46

Вниманию читателей предлагается простой в использовании обработчик шаблонов на языке PHP с поддержкой условных конструкций, циклов, подключения вложенных шаблонов и вызова функций. Время обработки шаблона составляет в среднем 20-70 мс. Для работы требуется подключение одного php-файла (есть и на GitHub). Код стабилен и применяется на нескольких работающих проектах.

Основы синтаксиса: переменные, условия, циклы

Перейдём сразу к практике и посмотрим, как выглядит шаблон, взяв для примера немного упрощенную версию HTML-кода сайта webew.ru:

<html>
<head>
    /* Многострочные комментарии - как в C или PHP */
   
    <title>{*title*}</title>
   
    <base href="{*=BASEHREF*}"> /* константа */
   
    /* условные конструкции: */
   
    {?*keywords*}
        <meta name="keywords" content="{*keywords*}">
    {?}
   
    {?*description*}
        <meta name="description" content="{*description*}">
    {?}
   
    /* условие с негативной частью */
    <link rel="stylesheet" href=" {?*default_css*} default.css {?!} special.css {?} ">  


</head>
<body>
    <div id="logo">
        <a href=""><img src="{*logo.image*}" alt="{*logo.alt*}"></a>
    </div>

    <div id="menu">
       
        /* цикл: */
       
        {%*menu*}
            <a href="{*menu:url*}">{*menu:title*}</a>
        {%}
   
    </div>
   
    <div id="content">
        {*content*}
    </div>
   
    <div id="footer">
        webew.ru &copy; {*year*}
    </div>
</body>
</html>
 

А вот соответствующий код PHP:


ini_set('pcre.backtrack_limit', 1024*1024); // (см. ниже)

$DATA['title'] = 'Webew: теория и практика веб-технологий ';

define('BASEHREF', 'http://webew.ru/');

$DATA['logo'] = array(
    'image' => 'i/logo.gif',
    'alt' => 'Логотип webew.ru'
    );

$DATA['menu'] = array(
    array('url' => 'css', 'title' => 'CSS'),
    array('url' => 'php', 'title' => 'PHP'),
    array('url' => 'seo', 'title' => 'Интернет-маркетинг'),
    array('url' => 'c', 'title' => 'C/C++')
    );

$DATA['content'] = 'Приветствуем вас на webew.ru!';


require_once 'websun.php'; // подключаем файл с шаблонизатором

$tpl = 'templates/main.tpl'; // путь к шаблону

$html = websun_parse_template_path($DATA, $tpl); // запуск шаблонизатора

echo $html; // получили обработанный шаблон, отдаем клиенту результат
 

Несмотря на то, что переменные $DATA['keywords'] и $DATA['description'] не установлены, при обработке шаблона не возникнет никаких ошибок или предупреждений.

Условная конструкция вида {?*keywords*} что-то {?} означает «вставить что-то, если в переменной, переданной шаблону (в данном случае $DATA) присутствует элемент keywords и при этом он не является пустой строкой, нулём, FALSE, NULL или пустым массивом». Соответственно, конструкция {?!*keywords*} ... {?} срабатывает, если какое-нибудь из этих условий не выполняется.

Шаблонизатор не генерирует ошибок или предупреждений в том случае, если какой-либо из запрошенных переменных или констант вообще не существует (вместо них молчаливо будет вставлена пустая строка) поэтому формат передаваемых данных может быть нестрогим.

В цикле ключи массива указываются через двоеточие — {*menu:title*}, а вне цикла через точку — {*logo.image*}.

Можно также обращаться к переменным глобальной области видимости, в т.ч. суперглобальным массивам. Для этого перед именем переменной нужно поставить знак доллара. Например, подстановка в шаблон переменной $_GET['foo'] выглядит так: {*$_GET.foo*}.

Вложенные шаблоны

Обычно код бывает удобно разбить на несколько шаблонов, которые затем подключать по мере необходимости. Пусть шаблон меню находится в файле menu.tpl. Тогда код из главного шаблона

<div id="menu">
    {%*menu*}
        <a href="{*menu:url*}">{*menu:title*}</a>
    {%}
</div>

в неизменном виде переместится в menu.tpl, а вместо него будет

...
<div id="logo">
    ...
</div>

{* +menu.tpl *} /* подключаем шаблон меню */

<div id="content">
...

Путь к шаблону может также передаваться в переменной. Например, если записать путь к шаблону меню в $DATA['menu_template'], то подключение его примет вид

{* + *menu_template* *}

Существует несколько способов указания путей к шаблонам.

Самый наглядный метод — это указание абсолютного пути к файлу шаблона в файловой системе — что-то наподобие

$tpl = '/home/webew.ru/htdocs/templates/main.tpl'

Аналогично, для подключения шаблона меню с помощью абсолютного пути приходится писать

{* +/home/webew.ru/htdocs/templates/menu.tpl *}

Если в начале пути к шаблону отсутствует слэш, то путь интерпретируется относительно месторасположения текущего шаблона (это особенно удобно для группы связанных шаблонов, которые становится легче читать, и к тому же можно все вместе переносить, не меняя при этом путей в них, если они записаны как относительные).

Обычно все шаблоны находятся в каком-то одном каталоге (или его дочерних) и шаблонизатору можно указать так называемый корневой каталог шаблонов — такой, относительно которого он будет интерпретировать пути к ним. Корневой каталог передается третьим аргументом:

websun_parse_template_path(
    $DATA,
    $tpl,
    '/home/webew.ru/htdocs/templates'
    );

(если корневой каталог при вызове функции не указан, за него принимается каталог, в котором находится исполняемый скрипт).

Сообщать шаблонизатору о том, что интерпретировать путь нужно относительно корневого каталога шаблонов, следует, поместив в начало пути символ ^:

$tpl = '^/main.tpl';

Можно указывать также путь к шаблону относительно корневого каталога веб-сервера (используется переменная $_SERVER['DOCUMENT_ROOT']). Для этого в начало пути нужно поместить знак доллара.

Таким образом, путь к одному и тому же шаблону (как при его подключении его из других шаблонов, так и при вызове websun_parse_template_path) можно указать четырьмя разными способами:

// пусть корневой каталог веб-сервера - /home/webew.ru/htdocs
// корневой каталог шаблонизатора - /home/webew.ru/htdocs/templates
// тогда следующие четыре записи эквивалентны:

$tpl = 'menu.tpl'; // путь относительно текущего шаблона
$tpl = '^/menu.tpl'; // относительно корневого каталога шаблонизатора
$tpl = '$/templates/menu.tpl'; // относительно корневого каталога веб-сервера
$tpl = '/home/webew.ru/htdocs/templates/main.tpl'; // абсолютный путь для ФС

При запуске шаблонизатора (вызов функции websun_parse_template_path) и при подключении не связанных друг с другом шаблонов рекомендуется использовать путь относительно корневого каталога шаблонизатора, в остальных случаях как правило удобнее пользоваться относительными путями.

По соображениям безопасности список возможных расширений файлов шаблонов по умолчанию ограничен набором *.tpl, *.html, *.css, *.js, *.xml. Изменить этот набор можно, воспользовавшись объектной формой вызова шаблонизатора и передав ей параметр allowed_extensions.

Передача во вложенный шаблон части массива данных

Зачастую подключаемый шаблон имеет дело не со всем массивом данных, а только с какой-то его частью (например, в шаблоне меню не нужны никакие переменные, кроме $DATA[menu]). Записывать каждый раз префикс массива в таком шаблоне становится излишним и неудобным, код шаблона загромождается. Чтобы этого избежать, подключаемому шаблону можно передать не весь массив, а лишь нужный элемент.

Вот как будут выглядеть основной шаблон и шаблон меню при таком подходе:

(основной шаблон)

...

{* + *menu* | menu.tpl *}

/* путь к шаблону в таком случае указываем через вертикальную черту */

...

(или другой вариант — с передачей пути в переменной:)

{* + *menu* | *menu_template* *}

Шаблон меню:

<div id="menu">
    {%**}
        <a href="{*:url*}">{*:title*}</a>
    {%}
</div>

Конструкции вида {**}, {%**} и {?**} означают обращение к корневой переменной, переданной в шаблон. А запись вида {* + шаблон *} есть укороченная форма конструкции {* + ** | шаблон *} (** — в подключаемый шаблон передается вся корневая переменная).

Можно пойти еще дальше и вынести код для элемента меню в отдельный шаблон:

<div id="menu">
    {%**} {* + *:* | menu-item.tpl *} {%}   
</div>

Здесь конструкция *:* указывает при итерации на каждый из элементов корневого массива и означает передачу их в подключаемый шаблон. Такая запись имеет и сокращенный вариант.

menu-item.tpl:

<a href="{*url*}">{*title*}</a>

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

Вызов функций и методов классов

Прямо из шаблонов можно вызывать функции PHP. Например:

Текущее время: {* @date("H:i:s") *}.

Случайное число от 1 до $DATA['max']: {* @rand(1, *max*) *}.

Массив $DATA['list'], "склеенный" пробелом: {* @implode(" ", *list*) *}.

Литералы массивов следует передавать в виде однострочной JSON-нотации, например:
{* @implode( " ", [1,2,3] ) *}
{* @print_r( { "a":"b",  "с":[5,6,7] } ) *}

Функции, которые можно вызывать из шаблонов, нужно зарегистрировать в специальной переменной под названием $WEBSUN_ALLOWED_CALLBACKS:

$WEBSUN_ALLOWED_CALLBACKS = array(
    'date',
    'rand',
    'implode',
);

При отсутствии вызываемой из шаблона функции среди зарегистрированных будет сгенерировано предупреждение.

Переменная $WEBSUN_ALLOWED_CALLBACKS должна быть объявлена в глобальной области видимости.

Результат работы функции передавать для подстановки в какой-нибудь другой шаблон, где этот результат будет принят в качестве корневой переменной. Например:

{* @rand(1,10) | rand-block.tpl *}

Имя функции можно также передавать шаблону в переменной. Например, если $DATA['rand_function'] = 'rand' и $DATA['rand_template'] = 'rand-block.tpl', то вызов будет выглядеть так:

{* @*rand_function*(1, 10) | *rand_template* *}

Можно вызывать статические методы классов, а также методы экземляров объектов:

$DATA['somedate'] = date_create(); // создан объект класса DateTime
{* @*somedate*->format("d.m.Y") *} - вызов метода экземпляра объекта
   
{* SomeClass::someMethod(*somedate*) *} - вызов статического метода класса

Регистрировать среди разрешенных к вызову следует по имени класса и метода:

$WEBSUN_ALLOWED_CALLBACKS = [
     'DateTime::format',
     'SomeClass::someMethod'
];

Скачать

Чтобы начать использовать шаблонизатор, достаточно скачать и подключить его php-файл.

Дополнительные возможности

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


Помимо websun_parse_template_path, принимающей путь к шаблону, есть еще функция websun_parse_template, которой вместо пути шаблона передается его содержимое:

$DATA = ...
$template = '
    {*keywords*}
    ...
    '
;
$html = websun_parse_template(
    $DATA,
    $template,
    '/home/webew.ru/htdocs/templates' // можно не указывать
    );

(на самом деле обработчик шаблонов реализован в виде объекта, создание и настройка которого для удобства инкапсулированы в функции websun_parse_template и websun_parse_template_path; если интересно, как это происходит, можно посмотреть код этих функций)


Условия можно конструировать с использованием сравнения:

{?*a=1*} a равно 1 {?}

{?!*a=1*} a не равно 1 {?}

{?*a>1*} a больше 1 {?}

{?!*a>1*} a не больше (т.е. меньше или равно) 1 {?}

{?*a=b*} а равно b {?}

{?*a="раз"*} a - это "раз" {?}
Условия можно делать вложенными:
{?!*a=1*}
    а не равно 1
    {?*a=10*} а равно 10 {?}
    {?*a=b*} а равно b {?}
{?}
В условиях можно использовать результат работы функций:
{?* @in_array(10, *a*) *} в a есть число 10 {?}
{?* @array_sum(*a*) > 15 *} сумма элементов a больше 15 {?}
{?* @array_sum(*a*) > @array_sum(*b*) *} сумма элементов a больше суммы элементов b {?}
и т.п.

Часть после знака сравнения интерпретируется как имя переменной, если только она не заключена в двойные кавычки (в этом случае для сравнения берется строка внутри кавычек) или же не состоит полностью из цифр (тогда берется соответствующее число).

Для ясности следует отметить, что условные конструкции можно использовать и внутри циклов. Например, можно выделить активный пункт меню, поместив его в <strong> вместо обычных ссылок:

$DATA['menu'] = array(
    array('url' => 'css', 'title' => 'CSS'),
    array('url' => 'php', 'title' => 'PHP', 'active' => TRUE), // активный пункт меню
    array('url' => 'seo', 'title' => 'Интернет-маркетинг'),
    array('url' => 'c', 'title' => 'C/C++')
    );

Шаблон:

{%*menu*}
    {?!*menu:active*}<a href="{*menu:url*}">{*menu:title*}</a>{?}
    {?*menu:active*}<strong>{*menu:title*}</strong>{?}
{%}

Следует отметить, что, несмотря на то, что для конкретной записи элемент 'active' может быть вообще не установлен, при работе шаблонизатора PHP не будет генерировать предупреждений или замечаний (т.е. засорять журнал ошибок), поскольку в шаблонизаторе для таких случаев есть в т.ч. проверка с помощью isset().


Иногда сократить запись можно с помощью конструкции вида {*var1|var2|var3|"раз"*}, которая заменяется на первую из перечисленных непустую альтернативу (в данном примере, если все переменные окажутся пустыми, будет подставлена строка "раз").

С помощью | можно также объединять в OR несколько условий:

{?* var_1="one" | var_2="two" *}
    var_1 равно "one" или var_2 равно "two"
{?}

А с помощью & - в AND:

{? *var_1="one" & var_2="two" *}
    var_1 равно "one" и при этом var_2 равно "two"
{?}


При использовании PHP 5.2.2 и выше следует обратить внимание на настройку pcre.backtrack_limit, которая ограничивает максимальный размер строки, обрабатываемой функциями семейства preg (по умолчанию это 100 Кб). Характерный признак недостаточно большой величины pcre.backtrack_limit — получение пустой строки в результате обработки шаблона в случае, когда этого быть не должно. Избежать этого можно, увеличив это значение (лучше с большим запасом — к растрате ресурсов это не приведет):

ini_set('pcre.backtrack_limit', 1024*1024); // 1 Mб



Итерация по одномерному массиву (вида $DATA['list'] = array(10,20,30,40,50)) делается очень просто. Например, вывести его элементы по одному в строке можно так:

{%*list*} {*list:*}<br> {%}

А вообще можно использовать массивы любой размерности (не только двумерные), а циклы строить — любой вложенности:

$DATA['cities'] = array(
    array(
        'id' => 1,
        'title' => 'Москва',
        'codes' => array(77, 97, 99, 177, 197),
        'neighbours' =>
            array('id' => 25, 'title' => 'Калуга'),
            array('id' => 32, 'title' => 'Тула'),
            array('id' => 47, 'title' => 'Владимир'),
            array('id' => 59, 'title' => 'Рязань'),
            array('id' => 134, 'title' => 'Тверь'),
            array('id' => 15, 'title' => 'Смоленск'),
            array('id' => 37, 'title' => 'Ярославль')
            ),
        ),
    array(
        'id' => 2,
        'title' => 'Санкт-Петербург',
        'codes' => array(78, 98),
        'neighbours' =>
            array('id' => 69, 'title' => 'Петрозаводск'),
            array('id' => 78, 'title' => 'Вологда'),
            array('id' => 10, 'title' => 'Новгород'),
            array('id' => 117, 'title' => 'Псков')
        ),
    ...
    );

Шаблон:

{%*cities*}
    <h1>{*cities:title*}</h1>
   
    <p>
    Автомобильные коды:
    {%*cities:codes*}
        {*cities:codes:*} /* список кодов - одномерный массив */
    {%}
    </p>
   
    <p>
    Соседние регионы:
    <br>
    {%*cities:neighbours*}
        <a href="/city/{*cities:neighbours:id*}">
        {*cities:neighbours:title*}
        </a>
        <br>
    {%}
    </p>
{%}

К элементам такого массива можно обращаться и вне цикла, например, {*cities.0.neighbours.1.title*} — 'Тула' и т.п.

Внутри цикла есть также возможность обратиться к ключу массива - с помощью инструкции ^KEY, например:

{%*cities*}
    № {*cities:^KEY*}. {*cities:title*}<br>
{%}

Аналогично, ^i и ^N внутри цикла — порядковый номер элемента в массиве, начиная с 0 и 1 соответственно.

А с помощью ^COUNT можно оперировать числом элементов в массиве:

Всего городов: {*cities^COUNT*}.
(перед ^COUNT нет двоеточия, т.к. его можно использовать и вне циклов)


Подключение шаблонов внутри циклов можно переписать покороче:

/* можно так: */
{%*menu*} {* +*menu:* | menu-item.tpl *} {%}

/* но лучше - так (перед именем передаваемой в шаблон переменной появился знак %) */
{* +*%menu* | menu-item.tpl *}

Аналогичное сокращение действует и для подключения шаблона внутри условия:

/* можно так: */
{?*menu*} {* +*menu* | menu-item.tpl *} {?}

/* но лучше - так (перед именем переменной появился знак вопроса) */
{* +*?menu* | menu-item.tpl *}

Есть возможность передавать в переменной не путь к шаблону, а непосредственно его содержимое (иногда это бывает удобно). Пользоваться этим можно так же, как и обычными вложенными подшаблонами:

    {* + >*tpl* *}
        /* фактически дополняем переменной  
        текущий шаблон; так можно, грубо говоря,
        сделать её содержимое динамическим
        с помощью шаблонизатора */
       
    {* + *subvar* | >*tpl* *}
        /* можно и часть массива */
       
    {* + *?subvar* | >*tpl* *}
        /* если в subvar что-то есть.. */
       
    {* + *%subvar* | >*tpl* *}
        /* пройтись по переменной в цикле */
   
    {* + *@module()* | >*tpl* *}
        /* использовать переменную как шаблон для подстановки результатов работы функции */


Можно отключить возможность использовать в шаблоне переменные глобальной области видимости и суперглобальные переменные ($_GET, $_SERVER, $_COOKIES и пр.). Для этого нужно передавать функциям websun_parse_template_path() и websun_parse_template() четвертый аргумент, равный TRUE:

websun_parse_template_path(
    $DATA,
    $template_path,
    '/home/webew.ru/htdocs/templates',
    TRUE
    );

Все такие переменные при обработке шаблонов будут заменены на пустые строки.


© Все права на данную статью принадлежат порталу webew.ru. Перепечатка в интернет-изданиях разрешается только с указанием автора и прямой ссылки на оригинальную статью. Перепечатка в печатных изданиях допускается только с разрешения редакции.
Добавить комментарий
Отображение комментариев: Древовидное | Плоское
NO USERPIC

skif1965

Здравствуйте
Очень познавательная статья.
Я из начинающих и если можно разъяснить некоторые вопросы , подскажите.
Как в $DATA['content'] = 'Приветствуем вас на webew.ru!'; вместо (Приветствуем вас на webew.ru!) вставить несколько готовых PHP файлов.
У меня почему то отображается только название.
И если это возможно как вызывать их в шаблоне.
Может как то не правильно выразился но суть понятна.
14.08.2011, 11:10
Ответить

1234ru

Что подразумевается под "вставить несколько готовых PHP файлов"?
Вы имеете в виду, что $DATA['content'] должна набираться в нескольких файлах?
Если так, то нужно примерно вот как:

$DATA['content'] = '';

require_once 'файл1.php';
require_once 'файл2.php';
...


В файлах:
$DATA['content'] .= 'что-то... (то, что требуется)';


И так - в каждом из файлов.
То, что не убивает нас, делает нас инвалидами.
16.08.2011, 12:06
Ответить

Morty

$DATA['content'] = '';

require_once 'файл1.php';
require_once 'файл2.php';
...

Нифига не работает.
Запрашиваемый файл вставляется вверх страницы, независимо от того где вставен шаблонный тег.
Сделайте функцию инклуда в шаблонизаторе.
Чтоб можно было вставить файл как-то так
{*include_file="filename.php"*}
17.01.2012, 01:36
Ответить

1234ru

Цитата:
Запрашиваемый файл вставляется вверх страницы

Тут что-то не так..
Сами файлы никуда не вставляются (если Вы, конечно, не имеете в виду, что в каждом из них написали echo).

Покажите, что у Вас происходит в файлах, или хотя бы расскажите на примере, чего хотите добиться.
То, что не убивает нас, делает нас инвалидами.
17.01.2012, 22:06
Ответить

Morty

1234ru
или хотя бы расскажите на примере, чего хотите добиться.

Morty
Чтоб можно было вставить файл как-то так
{*include_file="filename.php"*}

То есть я хочу, чтоб можно было подключать php файлы непосредственно в файле шаблона (some_template.tpl).
18.01.2012, 22:29
Ответить

1234ru

Подключать PHP-файл так, чтобы в нём выполнился код, шаблонизатор не позволяет.

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

В терминологии шаблонизатора модули - это обычные функции PHP, имя которых начинается с "module_".
Модули можно вызывать из кода шаблонов специальной конструкцией, при этом либо передавая результат их действия в какой-то шаблон, либо непосредственно заменяя им конструкцию в шаблоне.
Почитайте статью отсюда: http://webew.ru/articles/3609.webew#modules

Хотя не очень понятно, зачем Вам понадобилось прямо в шаблоне PHP-файлы вызывать.
Почему бы вместо этого просто не заполнить в этих файлах какие-либо переменные, а потом в каком-то общем шаблоне эти переменныые использовать?.
То, что не убивает нас, делает нас инвалидами.
19.01.2012, 11:28
Ответить
NO USERPIC

maber

а можно какой нибудь не большой пример с базой mysql?
25.08.2011, 18:30
Ответить

1234ru

Вообще шаблонизатор от базы никак не зависит.

Ну, можно представить, что данные страницы берутся из базы. Допустим, есть таблица pages:

CREATE TABLE pages (
    id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(255),
    keywords VARCHAR(255),
    description VARCHAR(255),
    text TEXT
)


Шаблон:

<html>
<head>
    <title>{*page.title*}</title>
    <meta name="keywords" content="{*page.keywords*}">
    <meta name="description" content="{*page.description*}">
</head>
<body>
   {* +header.tpl *}
   /* (тут некая "шапка" - логотип и т.д.) */

   <div class="content">
    {*page.text*}
   </div>
   
   {* +footer.tpl *}
</body>
</html>



Кусок кода, отвечающий за получение данных страницы:
// где-то раньше из строки адреса
// получили id страницы
$sql = "
    SELECT
        title,
        description,
        keywods,
        content
    FROM pages
    WHERE id = $pageid
    "
;
$DATA['page'] = mysql_getrow($sql);


Про mysql_getrow() см. здесь:
Удобные функции PHP для работы с MySQL.
То, что не убивает нас, делает нас инвалидами.
25.08.2011, 23:58
Ответить
NO USERPIC

maber

извиняюсь :) точнее хотел спросить про то что как все записи вывести с таблицы
26.08.2011, 10:55
Ответить

1234ru

Вообще это, опять же, к шаблонизатору не относится, но
SELECT * FROM таблица
То, что не убивает нас, делает нас инвалидами.
26.08.2011, 13:48
Ответить
NO USERPIC

maber

это понятно что так :) просто что-то у меня не получается построить шаблон :) использовал удобные функции)
27.08.2011, 10:13
Ответить

1234ru

Покажите код, который у вас данные получает.
То, что не убивает нас, делает нас инвалидами.
27.08.2011, 11:23
Ответить
NO USERPIC

WidowMaker

Спасибо, интересная статья, очень похоже на ClearSilver.
27.11.2011, 22:11
Ответить

1234ru

Спасибо за наводку.
Надо будет поглядеть на его исходный код, сравнить.
То, что не убивает нас, делает нас инвалидами.
28.11.2011, 03:59
Ответить
NO USERPIC

axules

Я в веб программировании соооовсем недавно и решил прокачаться, в общем я искал в нете шаблонизаторы и нашел вашу разработку =)
Уважуха =) хороший простой функциональный шаблонизатор!
НО! обязательно напишите что он требует PHP 5.3 (ну или не меньше 5.2.4)
Щас расскажу почему и как сделать его менее чувствительным к версии:
В коде шаблонизатора вы рвете код шаблона на куски при помощи регулярных выражений, но увы старые версии не тянут в регулярных выражениях подмены имен переменных
(с цифр на имена, вот она конструкция подмены - ?P<VAR> - это не работает)
Как исправить?
просто переписать код шаблонизатора - используемые переменные заменить на порядковый индекс в массиве разбора или в описании написать версию ПХП =)
Как я заметил? - условия воообще игнорировались, залез в исходник, вывел массив разбора - нема имен переменных =) ну это был хороший повод сменить версию пхп =)

В общем я вам благодарен за шаблонизатор!
13.12.2011, 20:45
Ответить

1234ru

axules, спасибо на добром слове :)

Что касается версий PHP. Тут меня ввела в заблуждение документация: именованные подшаблоны появились в PCRE 4.0, но в документации PHP соответствия версии PCRE я нигде не нашел.
Стоит добавить, что эту версию шаблонизатора я изначально разрабатывал на PHP 5.2+, поэтому про то, что именованные подшаблоны не поддерживаются более ранними версиями, узнал, когда всё уже было написано.
Переписывать код ради обратной совместимости с порядочно устаревшими версиями как-то лень, честно: обновиться до 5.2 сейчас обычно не проблема (чего нельзя сказать о 5.3), так что будет лишний повод идти в ногу со временем :)
То, что не убивает нас, делает нас инвалидами.
14.12.2011, 10:05
Ответить
NO USERPIC

axules

Блин а я как то не в теме различий 5.2 и 5.3=( лень сидеть читать =(
А что это настолько проблематично с 5.2 перенести систему на 5.3? Такие глобальные перемены?
(Мне то это удалось безболезненно - система в начале разработки да и ничего сверхъестественного не использую, но другие чтото не проверил ... ... ... надо бы проверить ...)
14.12.2011, 18:49
Ответить

1234ru

Трудности возникают при использовании устаревших функций (например, из семейства ereg) - код работает, но начинают сыпаться warning'и.
Если проект начал разрабатываться недавно, то проблем быть не должно.
То, что не убивает нас, делает нас инвалидами.
15.12.2011, 12:53
Ответить

1234ru

Версия 0.1.21 дополнена следующими возможностями (текст статьи обновлен соответственно):


1. Можно сравнивать между собой две переменные:
{?*a=b*}a равно b{*a=b*?}
{?*a>b*}a больше b{*a>b*?}

Чтобы сравнивать переменную со строкой, последнюю нужно заключить в двойные кавычки:
{?*a="раз"*}a - раз!{*a="раз"*?}

2. Конструкция вида {*var1|var2|var3|"раз"*} заменяется на первую из перечисленных непустую (!= FALSE) переменную (а в данном примере, если все переменные окажутся пустыми, будет подставлена строка 'раз').


3. С помощью инструкции ^COUNT можно получить в шаблоне количество элементов в массиве: вида {*var^COUNT*} (если переменная не является массивом, будет подставлена пустая строка).


4. Инструкция ^KEY позволяет получать ключ элемента массива внутри циклов:
{%*var*}
    {*var:^KEY*} - ключ
    ...
{*var*%}
То, что не убивает нас, делает нас инвалидами.
27.12.2011, 09:06
Ответить

Morty

Отличная статья, отличный шаблонизатор но есть вопрос...
К примеру мне нужно в цикл шаблонизатора вставить цикл for.
Делаю таким образом
$max =5;
$DATA['cycle'] = array(
    for ($x=0; $x <= $max; $x++) {
        array('t1' => 'T'.$x, 't2' => 'T'.$x, 't3' => 'T'.$x)
    }
);

В ответ получаю:
Parse error: syntax error, unexpected T_FOR, expecting ')' in index.php on line 21
21 строка
for ($x=0; $x <= $max; $x++) {

Помогите пожалуйста.
16.01.2012, 22:41
Ответить

1234ru

Morty, это у Вас ошибка в коде PHP, который формирует данные.
Нельзя прямо в объявлении массива писать цикл, надо так:

$DATA['cycle'] = array();
for ($x = 0; $x <= $max; $x++)
    $DATA['cycle'][] = array(
            't1' => 'T'.$x,
            't2' => 'T'.$x,
            't3' => 'T'.$x,
        );


Соответственно, в шаблоне пишете, например

$tpl = '
{%*cycle*}
    cycle[{*cycle:^KEY*}] - {*cycle:t1*}
    ---
{*cycle*%}'
;

echo websun_parse_template(
    $DATA,
    $tpl
    );


Результат:

    cycle[0] - T0
    ---

    cycle[1] - T1
    ---
   
    и т.д...
То, что не убивает нас, делает нас инвалидами.
17.01.2012, 22:10
Ответить

Morty

Спасибо
12.02.2012, 02:56
Ответить

Morty

Как сделать чтоб нормально работал вложенный цикл?
Есть два цикла. Первый выводит список категрий, второй - список подкатегорий для каждой категории (если подкатегории есть).
$all = mysql_result(mysql_query("SELECT COUNT(*) FROM `cat`"), 0, 0);
if ($all>0)
{
$DATA['cats'] = array();
$sql = mysql_query("SELECT * FROM `cat` ORDER BY `id` DESC");
while ($row = mysql_fetch_assoc($sql))
{
    $cat_id = $row['id'];
    $name = $row['name'];
    $catpost = mysql_result(mysql_query("SELECT COUNT(*) FROM `post` WHERE `cat_id`='$cat_id'"), 0, 0);
    $DATA['cats'][] = array(
        'punkt' => '<a href="'.$home.'/cat/'.$cat_id.'">'.$name.'</a> ('.$catpost.')<br>',
    );
}
$suball = mysql_result(mysql_query("SELECT COUNT(*) FROM `subcat` WHERE `pid` = '$cat_id'"), 0, 0);
    if ($suball>0){
        $DATA['subcats'] = array();
        $ssql = mysql_query("SELECT * FROM `subcat` WHERE `pid` = '$cat_id' ORDER BY `id` ASC");
        while ($srow = mysql_fetch_array($ssql))
        {
            $sid = $srow['id'];
            $sname = $srow['name'];
            $scpost = mysql_result(mysql_query("SELECT COUNT(*) FROM `post` WHERE `subcat_id` = '$sid'"), 0, 0);
            $DATA['subcats'][] = array(
                'subpunkt' => '&nbsp;&nbsp;<a href="/cat/'.$sid.'/1">'.$sname.'</a> ('.$scpost.')<br>',
            );
        }
    }
}

В шаблоне пишу так
           {%*cats*}
                {*cats:punkt*}
                {%*subcats*}
                    {*subcats:subpunk*}
                {*subcats*%}
            {*cats*%}


И оно отображает подкатегории возле каждой категории даже если подкатегории не относятся к данной категррии.
Как это исправить?
12.02.2012, 03:24
Ответить

1234ru

Morty
оно отображает подкатегории возле каждой категории даже если подкатегории не относятся к данной категррии.


Ну, Вы же массив так составили - вот оно и отображает.
Через print_r() сначала посмотрите, как ваш массив выглядит.

При нормальной структуре массива шаблон должен примерно вот так выглялдеть:

{%*cats*}
    {*cats:punkt*}
    {%*cats:subcats*} /* у каждой категории - свой подмассив с subcats */
        {*cats:subcats:subpunk*}
    {*cats:subcats*%}
{*cats*%}
То, что не убивает нас, делает нас инвалидами.
13.02.2012, 23:30
Ответить

Morty

Наверное проще будет модулем это дело подключить...
14.02.2012, 08:00
Ответить

Morty

....
16.01.2012, 22:43
Ответить

Virtus-pro

Здравствуйте, ошибка с условиями.

Не на одном хостинге уже сталкиваюсь с проблемой, что условия не работают

Вот с одно из хостеров:
Операционная система: Linux
Версия php: 5.2.6-1+lenny16
Версия GD: 2.0 or higher
Версия MySQL: 5.0.51a-24+lenny5
Размер БД MySQL: 40.2 кб.

код даже если вставить ваш:
<html>
<head>

</head>
<body>
{?*a=1*} a равно 1 {*a=1*?}

{?!*a=1*} a не равно 1 {*a=1*?!}

{?*a>1*} a больше 1 {*a>1*?}

{?!*a>1*} a не больше (т.е. меньше или равно) 1 {*a>1*?!}

{?*a=b*} а равно b {*a=b*?}

{?*a="раз"*} a - это "раз" {*a="раз"*?}


<br />
a = "{*a*}"

</body>
</html>


в php файле так
require_once 'websun.php'; // подключаем файл с шаблонизатором

$tpl = 'test.html'; // путь к шаблону
$DATA['a'] = "1";
$html = websun_parse_template_path($DATA, $tpl); // запуск шаблонизатора

echo $html; // получили обработанный шаблон, отдаем клиенту результат   


ошибки возникают типа
Notice: Undefined index: varname in /var/www/*****/data/www/*****/lib/templates/websun.php on line 242

Notice: Undefined index: value in /var/www/*****/data/www/*****/lib/templates/websun.php on line 250


Подмечу, если просто ставить условие, то ошибки нету, но и ничего не отображается при любом условии
Если в цикле делать условие, то возникает такая ошибка, содержимое цикла показывается, но условия не одни не выполняются


Хотя на других хостингах все прекрасно работает

Строки из файла с ошибками

$variable_value = $this->var_value($matches['varname']);
..........
$compare_value = ($matches['value'])


функция в целом откуда эти строки
    function parse_if($matches) {
        $variable_value = $this->var_value($matches['varname']);
       
        // применять variable_value
        // для получения значения $compare_value
        // нельзя при пустой строке,
        // т.к. variable_value устроена так,
        // что при пустой строке
        // она возвращает корневой массив
        $compare_value = ($matches['value'])
            ? $this->var_value($matches['value'])
            : FALSE ;
       
        if (isset($matches['sign']) AND $matches['sign']) {
            switch($matches['sign']) {
                case '=': $check = ($variable_value == $compare_value); break;
                case '>': $check = ($variable_value > $compare_value); break;
                case '<': $check = ($variable_value < $compare_value); break;
            }
        }
        else
            $check = ($variable_value == TRUE);
           
        $result = ($matches[1] == '?')
            ? $check
            : !$check ;
           
        $parsed_if = ($result)
            ? $this->find_and_parse_if($matches['body'])
            : '' ;
           
        return $parsed_if;
    }
15.02.2012, 17:22
Ответить

1234ru

Не работают именованные подшаблоны.
Получается так из-за того, что используется устаревшая версия библиотеки PCRE. Это странно, т.к. в PHP 5.2 и выше обычно PCRE достаточно новая (может, на том хостинге сборка такая).
Что показывает phpinfo()?
То, что не убивает нас, делает нас инвалидами.
15.02.2012, 19:00
Ответить

Virtus-pro

pcre


PCRE (Perl Compatible Regular Expressions) Support------------enabled
PCRE Library Version ---------------------------------------------------7.6 2008-01-28

Directive----------------------Local Value----------Master Value
pcre.backtrack_limit-----------100000-----------------100000
pcre.recursion_limit------------100000-----------------100000
16.02.2012, 13:30
Ответить

1234ru

Хм.. Странно. Довольно новая версия (новее, чем, по крайней мере, одна из тех, которые у меня работают успешно - вообще 6,6.06 от 2006 года), хотя 2008 год можно и обновить (лучше всего - PHP до 5.2.16, там вроде никаких критичных несовместимостей нет, не 5.3 все-таки).
Надо более тонкие отличия в версиях библиотек поискать..
То, что не убивает нас, делает нас инвалидами.
16.02.2012, 17:40
Ответить

Virtus-pro

На моем хостинге 5.3.9 , работает отлично. Это у друга такие ошибки лезут, просто он не сможет обновить пхп. Не его хост. Вот думал поможите.

Ну все равно спасибо за информацию
17.02.2012, 17:19
Ответить

1234ru

Честно говоря, просто не думал, что такие проблемы могут возникать на сравнительно новых версиях PHP.
Если это будет повторяться - придется мне переписать без именованных подмасок (там просто регулярное выражение сложное, без именования читается плохо).
Другу скажите, можем специально для него сделать версию без них, но тогда при обновлении шаблонизатора (если вдруг такое понадобится) придется править код руками.
То, что не убивает нас, делает нас инвалидами.
17.02.2012, 18:46
Ответить

Virtus-pro

Я буду очень благодарен если сделаете такую версию. А что там придется править руками? Если честно там всего 4-5 циклов во всем движке. Думаю не сложно будет поменять

Можно ваш icq ? Поподробнее обсудить хотелось бы
18.02.2012, 08:35
Ответить

1234ru

Ок, версию сделаю (постараюсь сегодня-завтра).
Да, поменять будет не очень сложно, просто тогда потребуется понаблюдать за работой - вдруг я где ошибусь при исправлении.
ICQ не пользуюсь, дам почту.
То, что не убивает нас, делает нас инвалидами.
20.02.2012, 05:28
Ответить

1234ru

Сделал версию без именованных подшаблонов (0.1.24b): http://webew.ru/f/nP0PVBWw.php (upd от 14.03.2012: есть более новая версия - 0.1.27).
Там изменены методы parse_if() и parse_vars_templates_modules().


Сейчас я вспомнил главную причину, почему использовались именованные подмаски: когда в рег. выражении есть условия, действующие на целые маски (вида '(...)?'), в массиве совпавших строк может меняться нумерация (по крайней мере, у меня сложилось такое впечатление).
Например, если в шаблоне вида /a(b)?(с)?/ не совпадут ни (b), ни (c), то в массиве совпадений второй и третий элементы ([1] и [2] - нумерация с нуля) будут вообще отсутствовать, тогда как если не совпадет (b), но совпадет (c), и [1], и [2] будут в наличии, при этом в [1] будет пустая строка.

Впрочем, нумерация подмасок, вроде бы, не меняется (т.е. соответствующий элемент в массиве либо вообще отсутствует, либо всегда имеет один и тот же номер ли).


В любом случае, если что-то будет работать не так, как ожидалось, нужно проверить, какой результат дает следующий код:

<?php
$pattern = '/(a)(b)?(c)?/';
$string = 'ac';
preg_match($pattern, $string, $matches);
print_r($matches);
?>


Должно быть:

Array
(
    [0] => ac
    [1] => a
    [2] =>
    [3] => c
)
То, что не убивает нас, делает нас инвалидами.
20.02.2012, 10:50
Ответить
NO USERPIC

sogdianacha

Здравствуйте,
А как быть, если в шаблоне smarty нужно использовать условие. Например, есть такой код:
<code lang="php">
<?
{foreach from=$show_meta_cat item=i}
<META content='{$ismkey}' name=Keywords>
<META content='Добавить компанию в {$ismdesc}' name=Description>
{foreachelse}
<META content='{$description}, {$name}' name=Keywords>
<META content='{$name}|{$descr}|{$description}' name=Description>

{/foreach}
?>
</code>
Но тут нужно добавить 3 условие: Например, на главной странице должна отображаться другие мета описания и ключевые слова. Эти, которые выше, они по применимы для страниц категорий и объявлений. Нужно сделать такое условия + еще условие что если пользователь на главной, сформировать мету такое, а если в категории, то название категории, а если пользователь на странице объявления, то генерировать из объявления мету.

Помогите мне решить эту задачу. Спасибо.
02.03.2012, 00:37
Ответить

1234ru

А покажите массив, который Вы скармливаете шаблонизатору (print_r) - (я в smarty не силен, поэтому не вполне понимаю, что шаблон означает)
То, что не убивает нас, делает нас инвалидами.
02.03.2012, 10:52
Ответить
NO USERPIC

axules

Ну ты вообще прикалолся =) а почему бы тебе не запостить там где люди постят про СМАРТИ? =) Тут ты врядли найдешь такую посещаемость пользователей смарти, которые могли бы тебе помочь =)
13.03.2012, 08:54
Ответить
NO USERPIC

axules

Вот еще баг:
в шаблоне ставлю просто двоеточие внутри цикла, например (реальный пример):
{%**}
: : : <br>
{**%}

вроде бы должен быть хтмл вида
: : :
: : :
: : :
Но получил:
0. 0. 0.
1. 1. 1.
2. 2. 2.

Версия 1.24б

Я конечно могу сам перебрать код и исправить, но потом будет сложно обновляться у вас =)
13.03.2012, 08:51
Ответить

1234ru

Спасибо за багрепорт!

Вот исправленная версия - websun-0.1.25-alt.php (теперь вместо b называется alt - от "alternative"), в ней такой цикл отрабатывает как положено.

Ссылки на основную версию обновил в головном сообщении.
То, что не убивает нас, делает нас инвалидами.
14.03.2012, 18:55
Ответить
NO USERPIC

sogdianacha

Спасибо, что ответили. Хоть на этом спасибо.
13.03.2012, 22:07
Ответить
NO USERPIC

axules

Увы и ах перестали работать условия сравнения с нулем...
{?*NODAT=0*}

я так полагаю, что теперь отсутствующее значение, пустая строка и фалсе не приравниваются к нулю ...
печаль =(
-------
Я ошибся ... Просто сравнение с нулем не работает ... у меня процедура возвращает 0, а шаблонизатор не может сравнить с нулем ...
-------
А вот и косяк
if (isset($matches[6]) AND $matches[6])
если $matches[6] = 0, то даже в условие не зайдет и не сравнит, вот этот энд вообще ни к чему ...
внутри условия стоит условие
$compare_value = ($matches[6])
? $this->var_value($matches[6])
: FALSE ;
так что самое разумное решение убрать "AND $matches[6]"
тогда все будет шикарно
что я и сделал ... жду обновленную версию с этим исправлением
---
вот мое временное решение (кусок кода из функции function parse_if($matches) )
if (isset($matches[6])) {
$compare_value = ($matches[6])
? $this->var_value($matches[6])
: FALSE ;

switch($matches[5]) {
case '=': $check = ($variable_value == $compare_value); break;
case '>': $check = ($variable_value > $compare_value); break;
case '<': $check = ($variable_value < $compare_value); break;
}
}

Ииии спасибо за отзывчивость разработчику =) Кстати код легко читаем, так что я думаю что каждый может помогать вам модифицировать, то есть не просто ругаться на ошибки, а по возможности предлагать решения!
Еще раз спасибо!
26.03.2012, 07:02
Ответить

1234ru

Верно подмечено (я в таких случаях пишу {?!*NODAT*}, поэтому как-то не замечал).
Точнее, у этого условия были свои предпосылки; я даже хотел было их Вам описать, но что-то на середине описания мне стало лень, и я решил, что это незначительно.
Вот обновленная версия: websun-0.1.26-alt.php. Проверьте, пожалуйста, и отпишитесь - если все нормально, обновлю и основную ветку.

Кстати, насчет веток. Что-то в последнее время лень стала всерьез выступать против поддержки версии с именованными подмасками.
Если какое-то время не будет поступать сообщений об ошибках в альтернативной версии - пожалуй, сделаю альтернативную главной и единственной.
Тем более если, Вы говорите, код даже там хорошо читается.

Вам отдельное спасибо за внимание к коду. Честно, не думал, что кто-то отважится его читать, особенно регулярные выражения :)
То, что не убивает нас, делает нас инвалидами.
26.03.2012, 11:34
Ответить
NO USERPIC

axules

Я на двух проектах посмотрел - вроде все работает =)
Мне еще предстоит много работы, так что если что не так будет - замечу и обязательно сообщу =) но надеюсь что все будет так как надо =) а то так не люблю сюрпризы такого рода =)
26.03.2012, 17:34
Ответить

1234ru

Cделал alt-версию основной (0.1.27): http://webew.ru/f/PrKZ2372.php

В 0.1.27 добавил скармливание переменной прямо в качестве шаблона (т.е. берется содержимое переменной и обрабатывается как шаблон; столкнулся с задачей, где это было удобным, вот и решил дополнить).
Пользоваться следует так же, как вложенными шаблонами:

{* + >*tpl* *}
{* + *subvar* | >*tpl* *}
{* + *%subvar* | >*tpl* *}
{* + *?subvar* | >*tpl* *}
{* + @module | >*tpl* *}
То, что не убивает нас, делает нас инвалидами.
30.03.2012, 15:46
Ответить
NO USERPIC

triungulin

*Время обработки шаблона составляет в среднем 20-70 мс.*

Доброго времени суток!
попробывал использовать - столкнулся с проблемой. все было нормально, пока не:
беру простой шаблон с перебором в цикле 700 элементов (выпадающий список )
Дак обрабатывается он у меня на коре два дуо 2 гигагерц 2 секунды в версии 0.123 в последней версии 0.1.27 вообще 4!!

как-то можно оптимизировать?
10.04.2012, 11:50
Ответить

1234ru

Что-то многовато для 700 элементов..
Покажите шаблон и пришлите массив данных файлом в виде serialize() - надо посмотреть конкретно.
То, что не убивает нас, делает нас инвалидами.
10.04.2012, 11:57
Ответить
NO USERPIC

triungulin

http://www.box.com/s/2dec1e94e011aa199c2b
10.04.2012, 12:31
Ответить

1234ru

И правда долго (у меня тоже почти четыре секунды работало).
Кое-что поправил, и версия 0.1.29 обрабатывает ваш шаблон меньше чем за десятую секунды.


Кстати, добавил простенький профилировщик (узкое место пришлось отлавливать, так что решил потратить чуть больше времени, добавив тогда уже инструмент). Он распечатывает некоторую статистику по времени выполнения и количеству вызовов функций шаблонизатора.
Чтобы его включить, нужно вызвать шаблонизатор с дополнительным аргументом:

$HTML = websun_parse_template(
        $DATA,
        $template,
        FALSE, // это корневой каталог шаблонизатора
               // когда установлен в FALSE - берется текущий
        TRUE // а это включение профилировщика
    );


Честно говоря, не сильно над ним старался, делает профилировщик только самое необходимое.
Но выпьем за то, чтобы в нем просто не было надобности - чтоб все работало быстро.


А затормозило вот что.
В регулярном выражении подмаска, ловящая имя переменной в if, была слишком нестрогая - ([^<>=]*) - то есть вообще любой символ, кроме тех, что участвуют в построении конструкции if в шаблоне (изначально я специально так сделал, чтобы дать возможность в именах переменных использовать что угодно; PHP это позволяет, и иногда это теоретически может быть удобно).
В результате символьный подкласс отправлялся гулять по всей строке, долго не терпя неудачу - на это и уходило всё время.
Эти три-четыре секунды почти полностью уходили на один прогон регулярного выражения для if по развернутому из цикла шаблону (который получался 120 килобайт длиной).
Так что я решил идти от строгого, составив символьный класс в явном виде, а не от противного.
Если кому-то понадобятся какие-нибудь символы (типа пробелов) - будем добавлять по мере необходимости.
То, что не убивает нас, делает нас инвалидами.
10.04.2012, 20:34
Ответить
NO USERPIC

triungulin

Спасибо за отзывчивость и оперативность! заметно помогло и сложному шаблону из примерно 50 элементов , 0.15 с против 0.5 с уже не так вызывающе....
11.04.2012, 05:55
Ответить

1234ru

Отлично!

Правда, тут неувязочка произошла.. В версии 0.1.28 допущена ошибка, нужно обновить следующей (я в предыдущем своем ответе обновил и в самой статье обновил ссылки).

Взялась ошибка вот откуда: вставлял код для профилирования и в одной из функций нечаянно замочил return :o (ошибка мелкая, нечего сказать )), но на вашем шаблоне этого не видно, потому что она для него не вызывалась).
То, что не убивает нас, делает нас инвалидами.
11.04.2012, 09:39
Ответить

deadka

1234ru, такой вопрос возник:

иногда возникает необходимость в ходе цикла узнать значение счетчика (ну например в случае, если в цикле выводится таблица, подсвечивать четные строки одним цветом, а нечетные другим). Есть ли такая возможность в твоём шаблонизаторе? Если есть, то приведи пожалуйста простой пример.
Через more, через less мы бредем в страну чудес...
06.06.2012, 06:32
Ответить

1234ru

На четность специальной проверки нет.
Нужно в таком случае завести внутри массива специальную переменную, которая говорит о четности.

Хотя конкретно пример с таблицей, на мой взгляд, лучше сделать стилями. А т.к. современные стили (типа :nth-child) поддерживаются не всеми браузерами, то правильнее, я считаю, повесить javascript.
То, что не убивает нас, делает нас инвалидами.
14.06.2012, 19:25
Ответить

bmg1

Подскажите как использовать в шаблоне такой массив:

$DATA['list'] = array(
    array(
        array('name'=>'Первое название01', 'link'=>'test01'),
        array('name'=>'Первое название02', 'link'=>'test02'),
        array('name'=>'Первое название03', 'link'=>'test03'),
        ...
    ),
    array(
        array('name'=>'Первое название11', 'link'=>'test21'),
        array('name'=>'Первое название12', 'link'=>'test22'),
        array('name'=>'Первое название13', 'link'=>'test23'),
        ...
    ),
    array(
        array('name'=>'Первое название21', 'link'=>'test1'),
        array('name'=>'Первое название22', 'link'=>'test2'),
        array('name'=>'Первое название23', 'link'=>'test23'),
        ...
    ),
    ....
);



И возможно ли как то в шаблоне определить <TR> к примеру есть массив, но он должен разбиваться по 4 или 3, каждый раз вставляя <TR> или к примеру если блочная верстка <div style="clear: both;"></div>
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
16.08.2012, 11:52
Ответить

1234ru

Разбиение на группы по строкам нужно сделать предварительно в коде, посчитав остаток от деления порядкового номера элемента на количество элементов в группе: если остаток равен единице - значит, имеем дело с первым элементом группы, надо открыть <tr> или <div>, если остаток равен нулю - значит, с последним и тег нужно закрыть.

Если у вас простой массив, в качестве порядкового номера можно брать индекс элемента в массиве, только прибавить единицу, т.к. индексы начинаются с нуля.

Допустим, остаток от деления хранится в ключе 'mod' каждого элемента. Тогда код шаблона будет таким:

<table>
    {%*list*}
   
    {?*list:mod=1*}<tr>{*list:mod=1*?}
   
        <td>
            <a href="{*list:link*}">{*list:name*}</a>
        </td>
   
    {?*list:mod=0*}</tr>{*list:mod=0*?}
   
    {*list*%}
</table>


Однако есть более изящное решение, которое не требует явно группировать записи в HTML-коде и позволяет добиться визуального разбиения на строки с помощью только CSS. Оно возможно в случае, если "ячейки" одинаковой ширины.

Суть решения в следующем: указать "ячейкам" такую ширину в процентах, чтобы в одну строку (т.е. 100%) помещалось ровно нужное количество ячеек (например, в случае четырех это будет 25%).
Еще нужно указать "ячейкам" display:inline-block (display:block привёл бы к тому, что каждая "ячейка" занимала бы всю строку, т.к. в случае display:block последующее содержимое всегда переносится на следующую строку, даже если по ширине остается свободное место (float не рассматриваем); display:inline игнорирует указание ширины; так что нужен именно display:inline-block).

В качестве "ячейки" можно выбрать любой HTML-тег, но чтобы обеспечить версиях Internet Explorer 7 и ниже, допустимо использовать только инлайновый элемент (т.к. IE7- не устанавливает display:inline-block для блочных элементов). Например, <span>.

У такого подхода есть один недостаток: нельзя, чтобы в HTML-коде между элементами списка было пустое пространство. Теги должны идти вплотную, без промежутков, иначе пустое пространство будет учтено при расчете ширины, и общая ширина строки уже будет равняться не 100%, а 100% плюс ширина пустот.

Из-за этого код в шаблоне становится менее читаемым: нужно либо располагать всё внутри цикла в одну строку, либо помещать отступы в комментарии:

<style>
    .list > span {
        display: inline-block;
        width: 25%; /* по четыре в строке */
    }
</style>

<div class="list">/* отступы - в комментариях
    */{%*list*}/*
    */<span>
        <a href="{*list:link*}">{*list:name*}</a>
    </span>/*
    */{*list*%}/*
*/</div>

Альтернативным вариантом является использование отдельного шаблона для элемента списка. Тогда код станет поприятней:

<div class="list">{* + *%list* | list-item.tpl *}</div>
/* между открывающим и закрывающим <div>
 * и фигурными скобками конструкции шаблонизатора
 * не должно быть пробелов
*/

Шаблон list-item.tpl также не должен содержать пробелов перед открывающим и после закрывающего корневых тегов:

<span>
    <a href="{*link*}">{*name*}</a>
</span>


Фактически разница между этими двумя подходами в том, что в первом случае при необходимости изменить количество записей в строке вы исправляете код PHP (меняете делитель), а во втором - изменяете CSS-свойство.

Второй подход обеспечивает более простую HTML-разметку, и, кроме того, не требует изменения логики серверной части, поэтому он более предпочтителен.
То, что не убивает нас, делает нас инвалидами.
16.08.2012, 13:54
Ответить

bmg1

А если возможность перебрать такой массив как я указал в первом сообщении?

   {%*list*}
        {%*list:^KEY*}

         <div>
            <a href="{*list:^KEY:link*}">{*list:^KEY:name*}</a>
         </div>

        {*list:^KEY*%}
    <div class="clear"></div>
    {*list*%}


Странно почему не работает?
К ключу в любом случае обращается.
Или вложенность не предусмотрена - по ключам?
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
16.08.2012, 14:17
Ответить

1234ru

Невнимательно прочитал ваш самый первый пример. Тут понадобится цикл в цикле, и выглядеть это будет вот как:

{%*list*}
    {%*list:*}
        <div>
            <a href="{*list::link*}">{*list::name*}</a>
        </div>
    {*list:*%}
    <div class="clear"></div>
{*list*%}


Чтобы было понятней, приведу пример обхода одномерного массива (типа array(1,2,3..)) :

{%*list*}
    {*list:*},
{*list*%}

(выдаст '1,2,3,..');
То, что не убивает нас, делает нас инвалидами.
16.08.2012, 16:26
Ответить

bmg1

Спасибо огромное
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
16.08.2012, 17:26
Ответить
NO USERPIC

Zhekkks

Неплохо. Спасибо.
13.10.2012, 22:10
Ответить
NO USERPIC

ruzvel

Добрый день!

задам глупый вопрос.

У меня на сайте меню идет из базы.

как должен выглядеть php и шаблон чтобы меню нормально отображалось.


С Уважением,
Илья
15.10.2012, 10:57
Ответить

1234ru

Покажите структуру таблицы в БД, где хранится меню (команда SHOW CREATE TABLE).

Также нужно, чтобы вы привели пример HTML-верстки страницы, где меню должно быть (то место, где меню, можно заполнить вручную - главное, чтобы сама структура верстки была понятна).
То, что не убивает нас, делает нас инвалидами.
15.10.2012, 13:58
Ответить
NO USERPIC

ruzvel

можете написать формулу? переменные то я сам проставлю...
18.10.2012, 19:17
Ответить

1234ru

Какую формулу? :(

Я могу вам запрос написать, если вы таблицу покажете. А так непонятно, что писать даже.
То, что не убивает нас, делает нас инвалидами.
18.10.2012, 20:57
Ответить
NO USERPIC

ruzvel

да самую обычную формулу:

в php выглядит так:
(общая формула)

в шаблоне выгляди так:
(общая формула)

главная проблема в том, что нужно создать из данных в БД массив:
как сделать массив я в принципе понимаю, а вот как этот массив подставить в шаблон
немного не понятно.

вот структура таблицы в БД:

cats CREATE TABLE `cats` (
`id` smallint(4) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL DEFAULT '',
`hidden` char(1) DEFAULT NULL,
`rang` smallint(4) DEFAULT NULL,
`txt` text,
`root` int(11) NOT NULL DEFAULT '-1',
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=MyISAM AUTO_INCREMENT=66 DEFAULT CHARSET=utf8
22.10.2012, 11:03
Ответить

1234ru

$sql = "
    SELECT
        id,
        name AS title,
        '' AS url -- не знаю, как у вас url формируется,
                  -- написал пустую строку для примера
    FROM cats
    WHERE hidden = ''
    ORDER BY rang DESC
    "
;

$PAGE['menu'] = mysql_gettable($sql);

$HTML = websun_parse_template_path(
        $PAGE,
        'main-template.tpl'
    );


Шаблон main-template.tpl:

(тут что-то, кроме меню)

/* подключаем шаблон для меню, передаем в него $PAGE[menu] */
{* + *menu* | menu.tpl *}

...


Шаблон menu.tpl (должен лежать рядом с main-template.tpl, ну или надо указать к нему путь):

<menu>
    {%**}
    <a href="{*:url*}">{*:title*}</a>
    {**%}
</menu>



Про mysql_gettable() см. здесь: http://webew.ru/articles/3237.webew
То, что не убивает нас, делает нас инвалидами.
22.10.2012, 15:10
Ответить
NO USERPIC

ruzvel

Спасибо все сработало, только поставил вместо $PAGE -> $DATE
29.11.2012, 09:55
Ответить
NO USERPIC

Hidalgo

Спасибо за подробные комментарии кода шаблонизатора
28.12.2012, 20:54
Ответить

1234ru

Да, комментарии и форматирование занимают значительно больше половины файла :)
Писал их в т.ч. потому что хотелось полнее донести идею простого шаблонизатора.
То, что не убивает нас, делает нас инвалидами.
28.12.2012, 21:54
Ответить
NO USERPIC

Hidalgo

Уважаемый Михаил!
Подскажите, как реализовать.
У меня есть языковой файлик, в котором хранятся все надписи на кнопках, названия, заголовки и прочее... Этот файлик инклюдится, формат такой:
$DATA['m_page'] = 'Главная страница';
$DATA['btenter'] = 'Войти';
$DATA['login'] = 'Логин';
$DATA['pass'] = 'Пароль';

Потом в шаблоне подставляю {*login*} {*pass*} и т.д.
Как быть, если переменная хранится в БД, и текст этой переменной должен браться из этого файлика?
К примеру в бд лежит переменная
$DATA['reg']

а в файлике так:
$DATA['reg'] = 'Зарегистрироваться';

Потом в шаблоне пишу {*reg*}
Соответственно на выходе получаю не текст Зарегистрироваться, а имя переменной
$DATA['reg']

Или может как то иначе хранить переменные в БД?
29.01.2013, 10:09
Ответить

1234ru

Перед вызовом шаблонизатора сделайте print_r($DATA), посмотрите, что в массиве - так ли он выглядит, как предполагалось?

Не очень понятно, что значит
Hidalgo
переменная хранится в БД, и текст этой переменной должен браться из этого файлика

То, что не убивает нас, делает нас инвалидами.
29.01.2013, 13:12
Ответить
NO USERPIC

Hidalgo

в бд я хочу хранить просто имя переменной, что бы сделать мультиязычный интерфейс.
К примеру в бд лежит переменная (к примеру название пункта меню)
$DATA['reg']

Этой переменной в языковом файле присваивается строка (какой то текст):
$DATA['reg'] = 'Зарегистрироваться';


похожий пример
29.01.2013, 14:37
Ответить

1234ru

Нужно, чтобы к моменту вызова шаблонизатора переменная уже содержала нужное значение - сам шаблонизатор обращаться к БД не умеет.

Ссылка что-то не открывается..
В общем, вам нужно из БД извлечь значение переменной, я правильно понимаю?
То, что не убивает нас, делает нас инвалидами.
30.01.2013, 13:46
Ответить
NO USERPIC

Hidalgo

Я знаю как извлекать данные из БД. Из бд я получаю URL (адрес ссылки) и title ссылки который представляет собой имя переменной, само значение этой переменной находится в языковом файле, который инклюдится в начале исполнения скрипта. Если я получаю массив из БД, подскажите, как в ячейке массива присвоить переменной значение?
Я просто думал, может можно как то поступить проще, как у вас реализовано с суперглобальными переменными.
30.01.2013, 14:21
Ответить

1234ru

Если у вас инклюдится языковой файл, и там указано присвоением элементу массива значения (как у вас в примере), то после этого массив должен оказаться заполненным. Я так и не понял, зачем при этом БД.
То, что не убивает нас, делает нас инвалидами.
30.01.2013, 21:14
Ответить
NO USERPIC

Hidalgo

В БД хранится название переменной. Допустим через админку создали пункт меню, который называется 'В начало' и ссылка на index.php. Но в бд хранится только имя переменной (такое же как в языковом файле), URL, порядок сортировки и виден ли этот пункт меню или нет.
В языковом файле ru-RU.utf8.lng пишем $DATA['reg'] = 'В начало';
В языковом файле en-EN.utf8.lng пишем $DATA['reg'] = 'Home';
В зависимости от настроек пользователя, инклюдится необходимый lng файл.

Чувствую что надо копать в сторону символических ссылок $$


31.01.2013, 04:27
Ответить

1234ru

Ну, если языковой файл инклюдится - значит, переменной присваивается нужное значение. Не понимаю, как может получаться, что
Цитата:
на выходе получаю не текст Зарегистрироваться, а имя переменной
$DATA['reg']


Попробуйте распечатать массив перед передачей его шаблонизатору и посмотреть, установлен ли в нем ключ 'reg'.
То, что не убивает нас, делает нас инвалидами.
31.01.2013, 07:27
Ответить
NO USERPIC

Hidalgo

В языковом файле:

После вывода массива и ссылки полученные из массива шаблонизатором
31.01.2013, 08:53
Ответить

1234ru

А, ну так у вас не происходит замена строки, совпадающей с названием переменной, на значение этой переменной.

Попробуйте каждой такой строке сделать eval() перед тем, как передавать в шаблонизатор.
То, что не убивает нас, делает нас инвалидами.
31.01.2013, 11:30
Ответить
NO USERPIC

Hidalgo

Не совсем понял, каким строкам сделать aval()?
Можете на этом примере показать?
<?php
$o_page = "Test";
$linkmain = "На главную";
$my_order = "Мои заказы";
$exit = "Выход";

$row = array(
    array('url' => 'css', 'title' => '$o_page'),
    array('url' => 'php', 'title' => '$linkmain'),
    array('url' => 'seo', 'title' => '$my_order'),
    array('url' => 'c', 'title' => '$exit')
    );
foreach ($row as $val ){
    echo $val['url'];
    echo $val['title'];
}
?>
31.01.2013, 11:58
Ответить

1234ru

В цикле нужно так:
foreach ($row as $key => $val)
    $row[$key]['title'] = eval($val['title']);
То, что не убивает нас, делает нас инвалидами.
31.01.2013, 13:09
Ответить
NO USERPIC

Hidalgo

http://clip2net.com/s/2MhQg

Все решил задачку)) без eval
Спасибо за помощь!
31.01.2013, 16:49
Ответить

bmg1

Странно работает массив в массиве.
при маленьких объемах все ок,
но к примеру 250 массивов в каждом из которых по 9 массивов, вешается.

<table>
{%*table.db*}
    <tr>
        {%*table.db:*}
            <td>{*table.db::*}</td>
    {*table.db:*%}
    </tr>
{*table.db*%}
</table>


Пытался разобраться - но мыслей нет.
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
03.01.2013, 04:45
Ответить

1234ru

А можно конкретный массив в виде serialize() текстовым файлом? Хочу потестировать.
То, что не убивает нас, делает нас инвалидами.
04.01.2013, 23:35
Ответить

bmg1

:(
как оказалось проблема была в функции:
krivie_ruki()


После чего подключил мозг и заработало

!!!Важно, если белый экран то скорей всего не хватает памяти, что можно поправить с помощью
ini_set('pcre.backtrack_limit', 1024*1024); // (см. ниже)

о чем и написано было автором в верху страницы.

Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
05.01.2013, 03:17
Ответить

bmg1

Не удается сравнить ключ массива:
{?*table.data::^KEY=img0*}
<img src="{*table.data::*}">
{*table.data::^KEY=img0*?}

ни так:
{?*table.data::^KEY="img0"*}
<img src="{*table.data::*}">
{*table.data::^KEY="img0"*?}

Если можно, возможно ли получать на основе результатов из модуля:
{?*@checkVar(*table.data::^KEY*)*}
<img src="{*table.data::*}">
{*@checkVar(*table.data::^KEY*)*?}

Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
02.02.2013, 14:19
Ответить

1234ru

Цитата:
Не удается сравнить ключ массива


Попробуйте с одним двоеточием вместо двух (во всех случаях - и в условии, и внутри цикла).

Использовать в сравнениях результат работы модуля, к сожаления, нельзя.
То, что не убивает нас, делает нас инвалидами.
02.02.2013, 19:31
Ответить

bmg1

с одним доветочием не работает так как массив таков, в простом варианте:
$data['table']['data'] = array(
    array( array('glow'=>'Title00'), array('dark'=>'Title01'), array('red'=>'Title02'), array('dark'=>'Title03'), array('red'=>'Title04'), ),
    array( array('dark'=>'Title10'), array('red'=>'Title11'), array('red'=>'Title12'), array('red'=>'Title13'), array('red'=>'Title14'), ),
    array( array('red'=>'Title20'), array('dark'=>'Title21'), array('dark'=>'Title22'), array('red'=>'Title23'), array('glow'=>'Title24'), ),
   
);
/*

{?*table.data::^KEY="glow"*}
<img src="{*table.data::*}">
{*table.data::^KEY="glow"*?}

 */


* - отредактировал сравнение, так понятнее
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
05.02.2013, 11:49
Ответить

1234ru

При такой структуре данных вам не хватает в шаблоне одного уровня вложенности:

{%*table.data*}
    {%*table.data:*}
        {%*table.data::*}
            {?*table.data:::^KEY="glow"*}
                <img src="{*table.data:::*}">
            {*table.data:::^KEY="glow"*?}
        {*table.data::*%}   
    {*table.data:*%}
{*table.data*%}
То, что не убивает нас, делает нас инвалидами.
05.02.2013, 13:24
Ответить

bmg1

Результат HTML вот такое:

            {?*"glow"="glow"*}
                <img src="Title00">
            {*"glow"="glow"*?}
       
   
       
            {?*"dark"="glow"*}
                <img src="Title01">
            {*"dark"="glow"*?}
       
   
       
            {?*"red"="glow"*}
                <img src="Title02">
            {*"red"="glow"*?}
       
   
       
            {?*"dark"="glow"*}
                <img src="Title03">
            {*"dark"="glow"*?}
       
   
       
            {?*"red"="glow"*}
                <img src="Title04">
            {*"red"="glow"*?}

Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
05.02.2013, 13:36
Ответить

1234ru

Вам нужно обновить шаблонизатор (скачайте по ссылке в статье - по ней всегда свежая версия), такая ошибка может возникать до версии 0.35
То, что не убивает нас, делает нас инвалидами.
05.02.2013, 14:05
Ответить

bmg1

:( как просто.

теперь работает и первый пример:
{?*table.data::^KEY="id"*}this ID!{*table.data::^KEY="id"*?}


Скажите как можно отслеживать изменения?
И можно ли как-то повлиять(предложить, пожертвовать, помочь)?
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
05.02.2013, 14:14
Ответить

1234ru

Изменения, честно говоря, никак не отследишь (кроме как в самом файле шаблонизатора - в начале идет список изменений по версиям), но обычно они довольно незначительные и основной функционал не затрагивают.
Ссылка в статье постоянно обновляется и указывает на последнюю версию шаблонизатора.

Вопросы и предложения пишите сюда - обязательно рассмотрим.

За желание помочь благодарю, и вообще спасибо на добром слове :)
То, что не убивает нас, делает нас инвалидами.
05.02.2013, 17:34
Ответить

bmg1

Имелось ввиду изменения - то есть обновление в проекте через GIT, SVN
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
08.02.2013, 09:52
Ответить

1234ru

Пока код хранится кустарно в виде ссылок на скачивание файла.
В дальнейшем, возможно, будет на github.
То, что не убивает нас, делает нас инвалидами.
08.02.2013, 12:18
Ответить

1234ru

Насчет изменений - вспомнил! Можно подписаться на эту статью, тогда будут приходить уведомления о комментариях, а я буду отписываться обо всех изменениях и новых версиях.
То, что не убивает нас, делает нас инвалидами.
05.02.2013, 17:36
Ответить

bmg1

спасибо
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
05.02.2013, 14:14
Ответить

bmg1

ниодин из вариантов:
                           {?*table.data::^KEY="id"*} ohohoh {*table.data::^KEY="id"*?}
                            {?*"id"=table.data::^KEY*} REVERT {*"id"=table.data::^KEY*?}
                            {?*table.data::^KEY=myKey.title*} myKey {*table.data::^KEY=myKey.title*?}
                            {?*myKey.title=table.data::^KEY*} REVERTmyKey {*myKey.title=table.data::^KEY*?}
                            {?*sub=table.data::^KEY*} SUBKey {*sub=table.data::^KEY*?}

не сработал

Но один сработал, что странно:
                           {?*myKey.title=table.data::^KEY*} REVERTmyKey {*myKey.title=table.data::^KEY*?}


при условии что есть:
//список возможных
$DATA['myKey'] = array(
    'id' => 'id',
    'img' => 'img',
    'title' => 'title',
    'edit' => 'edit',
    'word' => 'word'
);
 


и когда ключ равен title - то срабатывает
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
05.02.2013, 13:53
Ответить

bmg1

Может другой алгоритм использовать?

Идея состоит в том что бы вывести таблицу с разными типами данных.
В зависимости то названия столбца выводить её внешний вид.
Столбцы бывают разные все названия(ключи) не записать - пропадет смысл в шаблоне.
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
05.02.2013, 12:10
Ответить

bmg1

Обнаружился как понимаю баг:
при выводе цикла:
{%*list:data*}
   <option value="{*list:data:^KEY*}">{*list:data:*}</option>
{*list:data*%}


//сам массив
Array
(
    [imago.lv] => imago.lv
    [task.lv] => task.lv
    [www.task.lv] => www.task.lv

)


если list:data: равно строке по типу домена: imago.lv, task.lv, www.task.lv и так далее
то он показывает пустую строку.
Похоже что скрипт использует строку с точкой как слова подмены.

Может чтот поправить можно?

Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
09.02.2013, 14:14
Ответить

1234ru

Без полной структуры массива сказать сложно.
Вы уверены, что list:data, а не list.data? (по list тоже есть цикл?)
То, что не убивает нас, делает нас инвалидами.
11.02.2013, 16:39
Ответить

bmg1

Да уверен.

Реальный "работающий" код:
//PHP
//сам массив
$DATA['dd'] = Array(
    'imago.lv' => 'imago.lv',
    'task.lv' => 'task.lv',
    'www.task.lv' => 'www.task.lv'

);


<!-- HTML -->
{%*dd*}
   value={*dd:^KEY*} / {*dd:*}<BR>
{*dd*%}
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
11.02.2013, 19:37
Ответить

1234ru

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

Это не баг (теперь вспомнил). Такое поведение и закладывалось, поскольку корректным индексом ассоциативного массива считается состоящий только из word-символов (цифр, латинских букв и знака подчеркивания) и точек содержать, по идее, не должен.
Хотя шаблонизатор и позволяет работать с некорректными ключами некоторых типов (например, дефисы; и др.), точка, как вы правильно предположили, является специальным символом для самого шаблонизатора, причем на ней строится значительная часть его логики. Поэтому, боюсь, тут ничего не сделаешь.
То, что не убивает нас, делает нас инвалидами.
11.02.2013, 21:00
Ответить

bmg1

Как говорили в 90-х:
это не Баг а Фича :)

Ок.
Спасибо.

Буду логику менять
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
11.02.2013, 21:06
Ответить

bmg1

Обнаружил новые функции в версии websun 1.37
{?*var_1="one"|var_2="two"} ... {*var_1="one"|var_2="two"?}
 

но так и не удалось их реализовать
так как конструкиця типа:
{?*active="day"|active="night"*}
...
{*active="day"|active="night"*?}

не работает.
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
16.02.2013, 22:27
Ответить

1234ru

Цитата:

Обнаружил новые функции в версии websun 1.37
{?*var_1="one"|var_2="two"} ... {*var_1="one"|var_2="two"?}


У меня тут ошибка допущена - у закрывающих скобок не хватет звездочек (надо мне теперь серьезнее к комментариям в коде относится :) ),
Надо так:

{?*var_1="one"|var_2="two"*} ... {*var_1="one"|var_2="two"*?}


Ваш пример с *active="day"|active="night"* у меня сработал. Покажите массив.
То, что не убивает нас, делает нас инвалидами.
21.02.2013, 04:03
Ответить

bmg1


$DATA['active'] = 'day';

//или
$DATA['active'] = 'night';

 
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
21.02.2013, 09:05
Ответить

1234ru

$tpl = '
    {?*active="day"|active="night"*}
    day or night
    {*active="day"|active="night"*?}
    '
;

$DATE['active'] = 'day';

echo websun_parse_template(
        $DATE,
        $tpl
    );


У меня нормально отрабатывает - выдает "day or night". Вы файл шаблонизатора не забыли обновить?
То, что не убивает нас, делает нас инвалидами.
21.02.2013, 13:50
Ответить

bmg1

Попробуйте
$DATE['active'] = 'night';


У меня: websun 0.1.37
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
27.02.2013, 16:08
Ответить

1234ru

Да, глючок..
Исправлю в ближайшие дни.
То, что не убивает нас, делает нас инвалидами.
01.03.2013, 12:45
Ответить

1234ru

Исправил (ссылку в статье обновил).

Кстати. Добавил возможность связывать условия в if не только "OR", но и "AND". Делается это при помощи '&' :

{?*active="day"&active="night"*}
   it is day and night at the same time
{*active="day"&active="night"*?}

{?!*active="day"&active="night"*}
   not day and night at the same time
{*active="day"&active="night"*?!}
То, что не убивает нас, делает нас инвалидами.
04.03.2013, 17:59
Ответить

bmg1

Круто спасибо.

А можно ли получить результирующий код после шаблонизатора?
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
06.03.2013, 14:21
Ответить

1234ru

Ээ, не понял.. Что понимается под "результирующим кодом"?
То, что не убивает нас, делает нас инвалидами.
06.03.2013, 18:56
Ответить

bmg1

Я думал что хороший шаблонизатор может сгенерить PHP код из шаблона и сохранить его где-то или использовать в сессии пользователя.

Правда есть вопрос как проверить изменился ли шаблон :)
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
12.03.2013, 00:41
Ответить

1234ru

Если вы про кэширование, то его нет :)
(честно говоря, оно редко нужно; в тех случаях, когда нужно, лучше сделать снаружи, а не пихать это в шаблонизатор; потому что иначе он станет кэшировать и когда надо, и когда не надо)
То, что не убивает нас, делает нас инвалидами.
12.03.2013, 23:09
Ответить

bmg1

а как же оптимизация, маленькие ресурсы, быстрота работы.

надо или не надо перебирать шаблон просто решить:
file_exist();
если кому то надо обновить шаблоны - то он и папку с кешем может снести

У меня как раз делает из шаблонов PHP файлы и сам следит за существованием.
Но нет легкого генератора - что бы на лету, смотреть/пользоваться.
Ваш идеально подходит.

даже логика почти такая же:
у меня ключ: {} без звездочек.

О кстати, можно вопрос, а почему вы используете {**}, не достаточно ли {}?
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
12.03.2013, 23:44
Ответить

1234ru

Цитата:
а как же оптимизация, маленькие ресурсы, быстрота работы.

Это разговор не на один час.. :)

Я отмечу лишь некоторые моменты.

Маленькие ресурсы - часто противоречит кэшированию, т.к. под кэширование дополнительные ресурсы будут использованы всегда (диск, память); эффективность же кэша остается под вопросом.

Цитата:
надо или не надо перебирать шаблон просто решить:
file_exist();
если кому то надо обновить шаблоны - то он и папку с кешем может снести

Вот уже начались усложнения. Например, я не совсем понял вашу мысль в первом предложении :)
Потом.. Вот сейчас, пользуясь данным шаблонизатором, человек сделал шаблоны и знать не знает ни о какой необходимости удалять какую-то дополнительную папку, что-то настраивать и т.п.

Понятно, что ничего просто так не бывает. Еще и не на такое идут, чтобы быстрей работало.
Но давайте внимательно посмотрим, за что мы боремся.

Как отмечается в статье, среднее время обработки шаблона обычно составляет 20-70 мс. Понятно, что очень зависит от случая. Но, скажем так, по моему опыту редко превышает 100мс. Причем когда превышает, обычно все равно не является узким местом (потому что шаблон большой и сложный, а под такой шаблон нужно много разных данных, а много разных данных нужно выбрать, а это обычно сильно дольше; и т.п.).

Это я молчу про задержку передачи по сети и про отрисовку браузером. Не говоря уже о загрузке картинок и пр.
За что мы боремся? Так пользователь увидит страницу через 700 мс, а так - через 650. Разница видна не будет. И стоит ли забивать себе голову ради этой разницы?

Именно из-за этого я не хочу навешивать на шаблонизатор логику кэширования. Тот, кому кэширование нужно, пусть сделает его там, где ему нужно. Это будет прозрачно и индивидуально.

Да, отмечу, что все эти разговоры мы ведем на фоне популярности систем типа Drupal, которые для генерации одной страницы могут делать тысячи(!) запросов к базе данных.

Так что чем дольше живу, тем больше уважаю простоту :)

Цитата:
а почему вы используете {**}, не достаточно ли {}?

Бывает удобно писать прямо в шаблоне javascript. В нем {} - это объекты.
Квадратные (а тем более круглые) скобки плохо подходят, т.к. могут встречаться в обычном тексте. Так что из обычных скобок не подходили ни одни.. Ну, прикинул возможные варианты и остановился на {**}.
То, что не убивает нас, делает нас инвалидами.
13.03.2013, 01:30
Ответить

bmg1

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

Спасибо за столь развернутый ответ.
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
13.03.2013, 09:40
Ответить
NO USERPIC

Bamper

Цитата:

{?!*active="day"&active="night"*}
not day and night at the same time
{*active="day"&active="night"*?!}


вот такая конструкция что-то не хочет работать
если быть точным то в цикле

{%*my_array*}
{?!* my_array:id="1" & my_array:id="2" *}Работает!{* my_array:id="1" & my_array:id="2" *?!}
{*my_array*%}


конструкция срабатывает вне зависимости от id, т.е. всегда
10.09.2014, 01:06
Ответить

1234ru

Буквально такая конструкция означает "если my_array:id="1" & my_array:id="2" - ложь (?!), то вывести надпись".

my_array:id="1" & my_array:id="2" - очевидно, ложь всегда (т.к. id не может принимать сразу два значения), поэтому срабатывать будет в любом случае.
То, что не убивает нас, делает нас инвалидами.
11.09.2014, 15:13
Ответить
NO USERPIC

Bamper

Тогда не совсем понимаю как записать:
if($my_array['id']!=1 && $my_array['id']!=2){

}
12.09.2014, 02:36
Ответить

bmg1

Во первых желательно не использовать пробелов в конскрукции
Во вторых будьте внимательны к синтаксису, найдите отличия от вашего кода.
В третьих, ваш код:
{%*my_array*}
  {?!*my_array:id=1&my_array:id=2*}
   Работает! my_array: не 1 и не 2, а к примеру 0, 44 или 'икиаиви' или '' (пусто)
 {*my_array:id=1&my_array:id=2*?!}
{*my_array*%}


Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
12.09.2014, 08:05
Ответить

1234ru

bmg1
желательно не использовать пробелов в конскрукции

Сурово :)
Раньше и вообще нельзя было (вернее, выглядело так, что работало, но на самом деле работало неправильно).
Потом я однажды посмотрел на код шаблона и понял, что без пробелов очень сложно читать, и сделал, чтоб можно было с пробелами. Так что теперь можно :)

Что касается выражения.
{?!*my_array:id=1&my_array:id=2*} действительно срабатывает всегда, но не соответствует задаче.
Насколько я понимаю, Bamper хочет проверить, что элемент массива не равен ни единице, ни двойке, только не одновременно, а по отдельности.
Для этого нужно {?!* my_array:id="1" | my_array:id="2" *}.
То, что не убивает нас, делает нас инвалидами.
12.09.2014, 12:49
Ответить

bmg1

Я тоже так в начале подумал, но потом посмотрел на его пример PHP кода.

Хотя мысли читать, у меня пока только на расстоянии 3-5 метров получается.

А у вас какой радиус охвата? :)

P.S. Так может можно и в несколько строк вместо пробелов? Было бы красивей.
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
12.09.2014, 13:03
Ответить

1234ru

В несколько строк и сейчас можно (хотя изначально это и не задумывалось - можно сказать, случайно возникшая недокументированная возможность). Только вот шаблон начинает совсем монструозно выглядеть.
То, что не убивает нас, делает нас инвалидами.
12.09.2014, 15:18
Ответить

1234ru

Кое-что забыл в версии 0.1.38 (в условия штуки вида array^COUNT>1 забыл прописать).
Исправил в 0.1.40. Если уже успели скачать - обновите.

Кстати. Теперь прикрепленные PHP-файлы показываются прямо в браузере, можно сразу код смотреть.
То, что не убивает нас, делает нас инвалидами.
05.03.2013, 13:10
Ответить
NO USERPIC

Hidalgo

Здравствуйте Михаил!
У меня к вам снова вопрос.
php файл отдает картинку скриптом, код такой:
       
{
header('Content-type: image/jpeg');
readfile('test.jpg');
}

Как передать это изображение в шаблон?

21.02.2013, 13:28
Ответить

1234ru

Если вы хотите, чтобы у вас на странице показывалось изображение, нужно передавать не его само, а тег <img> (вписать в шаблон что-то вида <img src="test.jpg">).
Здесь работа с шаблоном сводится к простой передаче в него адреса картинки.
То, что не убивает нас, делает нас инвалидами.
21.02.2013, 13:52
Ответить
NO USERPIC

Hidalgo

Да немного разобрался, спасибо.
Но как из скрипта, у которого есть шаблон, посмотреть картинку.
PHP файлик инклюдится в index.php по гет запросу do=myscript.
В нем содержится этот код:
if(isset($_GET['attach']))
{
     $DATA['complete_image'] = $_GET['attach'];
}
   
if(isset($_GET['img']))
{
     header('Content-type: image/jpeg');
     readfile('http://localhost/'.$_GET['img'].'.jpg');
}


в шаблоне пишу так:
<img src="?do=myscript&img={*complete_image*}">


Что бы посмотреть картинку, я должен пройти по адресу
http://localhost/?do=myscript&attach=image_01
По сути скрипт подставит в шаблон имя файла, а сам шаблон должен показать картинку.
В чем ошибка?

P.S. работает если только этот файлик вынести отдельно от шаблонизатора.
т.е. к примеру простой запрос <img src="images.php?img=image_01"> срабатывает
21.02.2013, 16:01
Ответить

1234ru

Картинку лучше выводить отдельным скриптом, а в HTML-коде следует писать абсолютный (т.е. начинающийся со слэша) адрес этого скрипта. Например, <img src="/images.php?img=image_01">
То, что не убивает нас, делает нас инвалидами.
22.02.2013, 19:36
Ответить
NO USERPIC

Hidalgo

Спасибо за помощь!
24.02.2013, 12:38
Ответить

bmg1

Бажок нашел.
Конструкция:
{?*list:kind="1"&list:accomm="0"*}
TEXT
{*list:kind="1"&list:accomm="0"*?}


и такая:
{?*list:kind="1"*}{?*list:accomm="0"*}
TEXT
{*list:accomm="0"*?}{*list:kind="1"*?}


результаты разные, а по сути должен быть одно и тоже.

с нулем конструкция типа && работает подругому
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
12.03.2013, 18:25
Ответить

1234ru

Да, бажок был - при развороте циклов забыл добавить поиск после & (типа {?*...&list:key..*}), в результате такие элементы массива не разворачивались.
Исправил. На исправленном оба случая из вашего примера работают одинаково.

Обновил ссылку в статье - попробуйте.
То, что не убивает нас, делает нас инвалидами.
12.03.2013, 23:22
Ответить

bmg1

Спасибо!

Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
12.03.2013, 23:35
Ответить
NO USERPIC

axules

Я как один из самых матерых пользователей этого шаблонизатора скажу свое слово =)))) Заебись! =)
Использую его год, сразу вкурил что да как, как то раз разобрал код (не подружился он в некоих местах с стареньким пхп) и скажу - я написал бы точ в точ так же! В общем использую его постоянно и везде.
А в длинном коменте про кеширование и всякую шнягу - согласен на все 100%, не стоит усложнять плагин инструментарием используемым в 5% случаев. Как-то написал алгоритм и меня не устроила его реализация - показалось как то не изящно и медленно работал, полез в гугл, нашел реализацию алгоритма, зашитую в какой-то популярный фреймворк, ну и что вы думаете, по тестам при одинаковых условиях он оказался в 5 раз медленней, так что популярность фреймоворков никоим образом не связана с их производительностью =)
14.03.2013, 17:04
Ответить

1234ru

axlues, спасибо на добром слове :)
То, что не убивает нас, делает нас инвалидами.
14.03.2013, 18:44
Ответить

1234ru

Обновил до версии 0.1.43. Имена переменных в if'ах теперь обрабатываются более демократично (раньше можно было только буквенно-цифровые, сейчас - что угодно, кроме точек, как и в других местах, где имеют дело с переменными).
Немного поправил профилировщик (который все же оставляет желать лучшего), теперь общее время показывает правильно.
Кстати. Со включенным профилировщиком время обработки шаблонов возрастает раза в полтора как минимум.
То, что не убивает нас, делает нас инвалидами.
22.03.2013, 13:11
Ответить

bmg1

Заметил бажок.

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

вот пример:
{* @myFunction("sorry, man") *}
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
14.05.2013, 15:25
Ответить

1234ru

Вызов модуля воспринимает запятую как разделитель аргументов, даже внутри кавычек, т.к. изначально вызов модуля предназначался для случаев, когда аргументы либо совсем простые, либо передаются в виде переменных (типа {* @myFunction(*var1*, *var2*) *}).

К сожалению, научить шаблонизатор учитывать кавычки сложно, поэтому рекомендую поместить строку в переменную и передавать её в модуль уже как переменную.
То, что не убивает нас, делает нас инвалидами.
14.05.2013, 16:19
Ответить

bmg1

Спасибо
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
15.05.2013, 05:15
Ответить

1234ru

Обновил до версии 0.1.44.
Обработка циклов сделана более "демократичной" и в качестве аргумента для итерации может принимать элементы массивов с нелатинскими ключами.
Т.е., например, если есть массив вида $cities['Москва'] = (тут какой-то список), то по элементу cities.Москва можно пройти циклом (а раньше было нельзя, т.к. рег. выражение строго ограничивало возможные ключи).
То, что не убивает нас, делает нас инвалидами.
14.05.2013, 22:01
Ответить
NO USERPIC

andy777

Классный шаблон!
Начал его у себя использовать и сразу появился вопрос.
Я хочу реализовать следующую схему работы:
1) приходит запрос. Роутер его отрабатывает, вытаскивает нужные данные (например список статей), определяет нужный шаблон, и начинает его выводить
2) шаблон начинает парситься и подтягивает нужные ему в данный момент дополнительные данные. (меню, картинки, и т.п.)

Как я понял, реализовать это можно путем вызова функций прямо из шаблона. Однако остались вопросы:
1) можно ли вызывать не функцию, а метод определенного класса?
2) как в шаблоне можно использовать результаты исполнения этой функции? Например функция внутри определяет имя подгружаемого подшаблона (например "menu.tpl") и задает переменные для него (например массив $menu с пунктами меню).

Мне кажется часто удобно прямо из шаблона вытаскивать нужные тебе данные. Ведь если делать стандартно, то я (программист) должен всегда знать в каком шаблоне дизайнер использует какие информационные блоки. И если дизайнер что то поменяет, то я должен это отследить и поправить у себя.

Или может есть красивее решение?
10.06.2013, 15:10
Ответить

1234ru

Честно говоря, шаблонизатор рассчитан, прежде всего, на подход, когда в первую очередь подготавливаются все необходимые данные, которые затем передаются в шаблон.
Этот подход реализует архитектурную идеологию программирования, которая позволяет максимально локализовать логику приложения на уровне собственно PHP (т.е. прямо в коде), а представление данных вынести в шаблоны.
Говоря по-простому, это означает, что вы как программист определяете, какие данные будут предоставлены дизайнеру/верстальщику для шаблонов, а он уже решает, в каком виде их выводить на странице.
Да, при этом дизайнер самостоятельно не сможет без помощи программиста получить нужные ему данные, если они не предусмотрены, но от этого больше порядка: легче искать ошибки и утечки ресурсов.

Тем не менее, возможность вызвать определенный программный код прямо из шаблона существует, и реализуется она с помощью т.н. модулей - см. соответствующий раздел данной статьи.

Цитата:
можно ли вызывать не функцию, а метод определенного класса?

Здесь всё не так просто..
Возможность вызывать из шаблона любую функцию таит в себе опасность: представьте, кто-нибудь в шаблоне возьмет и напишет @mysql_query("DROP DATABASE ...") и т.п.
Именно по этой причине введено правило, по которому имя модуля должно обязательно начинаться с какого-то префикса, который подставляется уже после передачи в шаблон - как раз чтобы произвольную функцию вызвать было нельзя и набор доступных таким образом функций контролировал программист на стороне PHP.
Не будь этой подстановки, реализовать вызов из шаблона методов объектов было бы несложно. Но она есть, причем действует очень просто: префикс подставляется к имени функции слева. В случае же с объектом непонятно, куда подставлять - к имени объекта или к имени метода. Да и еще какие-нибудь трудности по пути наверняка обнаружатся.

По этим причинам поддержку вызова методов объектов из шаблона обещать не могу.
Советую, по возможности, вынести логику в код и к моменту вызова шаблонизатора подготовить максимум необходимых данных, а для тех случаев, где это совсем не подходит, в качестве оберток использовать функции-модули.
То, что не убивает нас, делает нас инвалидами.
11.06.2013, 00:09
Ответить
NO USERPIC

andy777

Я понимаю, что вызов данных из шаблона - это вопросы безопасности и правильности кодирования.
Однако некоторые блоки в шаблоне могут требовать значительных ресурсов для получения данных. Например иерархическое меню каталога товаров интернет магазина из 200-300 групп с произвольной иерархией. Или лента новостей с данными с других сайтов. И прочее.
И при правильной логике проектирования получается я должен всегда готовить все такие данные, даже если для данной страницы дизайнеру не нужно их отображать.
Я вижу выход только в жестком разделении шаблонов программистом, сопоставление каждому шаблону своего класса, который бы готовил только нужные данные. Но при такой схеме дизайнер вообще намертво зависит от программиста.
Может есть лучше вариант? Посоветуйте объектную модель для работы с шаблонами на примере, допустим, интернет магазина.

А что касается вызовов функций может тогда реализовать возможность вызова методов самого класса шаблонизатора websun? Точнее его наследованных потомков. Было бы красиво. И возможностей дополнительных много.
11.06.2013, 07:01
Ответить

1234ru

Цитата:
при правильной логике проектирования получается я должен всегда готовить все такие данные, даже если для данной страницы дизайнеру не нужно их отображать.

Зачем же всегда?
Вы ведь на основании адреса страницы можете понять, какие данные понадобятся, а какие - нет.

Если хотите все же дать дизайнеру возможность выбирать самостоятельно - сделайте для него модули-обертки. Хотя их и придется делать каждый отдельно, наверняка они будут немногочисленны (дизайнеру вряд понадобится много), а код у них будет совсем простой и времени у вас на это уйдет совсем немного.

Цитата:
может тогда реализовать возможность вызова методов самого класса шаблонизатора websun?

Честно говоря, это идеологически неправильно. Шаблонизатор предназначен только для обработки шаблонов, и если перекладывать на него какие-то еще обязанности, то можно потом сильно запутаться.


Если не очень понятно, как всё вышеописанное с удобством применять в реальной жизни, можем разобрать на каком-нибудь конкретном вашем примере.
То, что не убивает нас, делает нас инвалидами.
11.06.2013, 10:38
Ответить
NO USERPIC

andy777

Если не трудно, давайте разберем.
Пример: сайт - витрина магазина.
Имеем два вида страниц:
1)страница группы товара. На ней перечисляются все товары входящие в эту группу
2)страница - карточка товара. На ней отображаются все поля одного товара.
Соответственно имеем 3 шаблона:
page.tpl - главный шаблон
page_group.tpl - вложенный шаблон для страницы группы товара
page_product.tpl - вложенный шаблон для страницы карточки товара

Решение:
Имеем следующие классы
<?php
//задаем общие переменные окружения для работы
date_default_timezone_set('Europe/Moscow'); //временная зона
header("Content-type: text/html; charset=UTF-8"); //кодировка
error_reporting (E_ALL); //показывать все ошибки

class Page_Group{
    function show($id){
       
        //инициируем шаблон
        require_once 'websun.class.inc';
       
        $array_params = array();
        //задаем переменные необходимые для шаблона 'page.tpl'
        $array_params['tmpl_name'] = 'page.tpl';
        $array_params['title'] = 'Товары в группе';
       
        $menu_obj = New Aplic_Groups();
        $menu = $menu_obj->get_groups();//получаем массив с пунктами меню
        $array_params['menu'] = $menu;
       
        $array_params['tmpl_sub_name'] = 'page_group.tpl';//имя вложенного шаблона
        //задаем переменные необходимые для шаблона 'page_group.tpl'
        $prod_obj = New Aplic_Product();
        $products = $prod_obj->get_product_group($id);//получили список товаров
        $array_params['product_list'] = $products;
       
        $W = new websun($array_params, SITE_PATH_TAMPLATE);
       
        $tpl = $W->get_template('page.tpl');
        $W->templates_current_dir = pathinfo( $W->template_real_path(SITE_PATH_TAMPLATE), PATHINFO_DIRNAME ) . '/';
        $string = $W->parse_template($tpl);
       
        echo $string;
    }
}
class Page_Product{
    function show($id){

        //инициируем шаблон
        require_once 'websun.class.inc';

        $array_params = array();
        //задаем переменные необходимые для шаблона 'page.tpl'
        $array_params['tmpl_name'] = 'page.tpl';
        $array_params['title'] = 'Товары в группе';

        $menu_obj = New Aplic_Groups();
        $menu = $menu_obj->get_groups();//получаем массив с пунктами меню
        $array_params['menu'] = $menu;

        $array_params['tmpl_sub_name'] = 'page_product.tpl';//имя вложенного шаблона
        //задаем переменные необходимые для шаблона 'page_product.tpl'
        $prod_obj = New Aplic_Product();
        $product = $prod_obj->get_product_id($id);//получили список товаров
        $array_params['product'] = $product;

        $W = new websun($array_params, SITE_PATH_TAMPLATE);

        $tpl = $W->get_template('page.tpl');
        $W->templates_current_dir = pathinfo( $W->template_real_path(SITE_PATH_TAMPLATE), PATHINFO_DIRNAME ) . '/';
        $string = $W->parse_template($tpl);

        echo $string;
    }
}

Как видно из кода приходится в каждом таком классе инициировать все переменные главного шаблона.
Можно конечно объединить эти классы под одним родителем (например class Page) и вынести инициализацию переменных главного шаблона в него. Но тогда все равно придется в дочернем классе писать что то типа:
$array_params['tmpl_name'] = $this->tmpl_name;

ведь класс шаблонизатора я все равно создаю в дочернем классе Page_Group и параметры шаблона должен задать именно здесь.

Короче, посоветуйте на примере данной задачи как правильнее организовать структуру классов.
13.06.2013, 14:43
Ответить

1234ru

Прежде всего, я бы вообще вынес генерацию HTML-кода за пределы класса, оставив на его стороне только задачи по подготовке собственно данных.

Разбор адреса страницы и определение того, какие нужны данные - это другая задача, и в коде её удобнее представлять отдельно.

<?php
//задаем общие переменные окружения для работы
 ...

# подключаем шаблонизатор
require_once (websun)

$PAGE = array(); // это массив для передачи шаблонизатору
                 // его будем заполнять нужными данными

# А вот теперь разбираем адрес страницы и, по необходимости,
# получаем нужные данные с помощью классов
# (не знаю, какого вида у вас адреса, поэтому примеры лишь абстрактные)

if (адрес страницы соответствует карточке товара) {
   
    # на основании адреса страницы определяем
    # id товара и записываем его в $product_id
   
    $product_object = new Page_Product;
   
    # получаем данные товара
    $product_data = $product_object->show($product_id);
   
    # теперь нужные данные передаем в массив для шаблонизатора
    $PAGE['title'] = $product_data['title'];
    $PAGE['menu'] = $product_data['menu'];
    $PAGE['product'] = $product_object->get_product_id($product_id);
   
    # имя вложенного шаблона также передаем
    $PAGE['template'] = 'page_product.tpl'; // # (как он подключается, будет показано ниже)
}

elseif (адрес страницы соответствует группе товара) {
   
    # На основании адреса определяем id группы товара - $group_id
   
    $group_object = new Page_Group;
   
    # Далее - снова получаем необходимые данные с помощью классов
   
    $group_data = $group_object->show($group_id);
   
    $PAGE['title'] = $group_data['title'];
    $PAGE['menu'] = $group_data['menu'];
   
    $prod_obj = New Aplic_Product();
    $PAGE['product_list'] = $prod_obj->get_product_group($group_id);//получили список товаров;
   
}
// и т.п.

# Теперь вызываем шаблонизатор и получаем HTML-код страницы

$HTML = websun_parse_template_path(
        $PAGE,
        'page.tpl',
    )

echo $HTML;

?>


Соответственно, page.tpl должен выглядить примерно так:

<!DOCTYPE ...>
<html>
<head>
    <title>{*title*}</title>
    ... 
</head>
<body>
    /* вот здесь мы и подключаем вложенный шаблон: */
    {* + *template* *}
</body>
</html>


При такой схеме нагрузка по взаимодействию с шаблонизатором с классов снимается, и, как следствие, необходимость связывать их наследованием устраняется.
То, что не убивает нас, делает нас инвалидами.
14.06.2013, 07:55
Ответить

wwwplaton

Здравствуйте, нужно вывести масив. Но при этом один из его результатов должен быть обработан функцией. Не подскажите как это сделать?
19.08.2013, 04:57
Ответить

1234ru

Обработку массива следует проводить перед тем, как передавать его в шаблонизатор (сам шаблонизатор менять данные не позволяет).
То, что не убивает нас, делает нас инвалидами.
19.08.2013, 07:49
Ответить

wwwplaton

Спасибо за ответ.
Я просто пытался оттолкнутся от:
function module_year()
Но не понимал чуть синтаксиса.
А оказалось что я совсем не чего не понял. Мне остается уточнить.
В функцию примера module_year нельзя передать переменную для обработки?
19.08.2013, 13:24
Ответить

1234ru

Можно: {* @module_year(*имя переменной*) | шаблон.tpl *}
разделе статьи про модули есть аналогичный пример).

Если переменная является массивом, можно передавать его не весь, а только конкретный элемент:
@module_year(*var.key1*)

Но вообще вызова модулей следует, по возможности, избегать. Лучше обрабатывать массив в прямо в PHP, до передачи его шаблонизатору.
То, что не убивает нас, делает нас инвалидами.
19.08.2013, 17:18
Ответить

wwwplaton

Теперь все понял, и уже делаю это в php/
Спасибо за помощь ;)
19.08.2013, 17:21
Ответить
NO USERPIC

mkden

пустая страница при выводе массива в котором больше 100 значений!

Array ( [0] => Array ( [user_rank] => 1 [iconrank] => [iconbot] => [name] => Icesword73 [urlname] => Icesword73 [scores] => [score] => - [deaths] => [time] => 01:55 [cscore] => [username] => ) [1] => Array ( [user_rank] => 2 [iconrank] => [iconbot] => [name] => gabriel07 [urlname] => gabriel07 [scores] => [score] => - [deaths] => [time] => 00:56 [cscore] => [username] => ) [2] => Array ( [user_rank] => 3 [iconrank] => [iconbot] => [name] => zack2051 [urlname] => zack2051 [scores] => [score] => - [deaths] => [time] => 01:37 [cscore] => [username] => ) [3] => Array ( [user_rank] => 4 [iconrank] => [iconbot] => [name] => JRGONG [urlname] => JRGONG [scores] => [score] => - [deaths] => [time] => 01:49 [cscore] => [username] => )... )
02.10.2013, 17:53
Ответить

1234ru

Сделайте побольше значение pcre.backtracklimit (в этой статье есть более подробные инструкции).

P.S. Пожалуйста, уберите из комментария распечатку массива (слишком длинный получается).
То, что не убивает нас, делает нас инвалидами.
02.10.2013, 20:34
Ответить
NO USERPIC

axules

Зашел обновиться =) И решил еще раз написать о том какой классный шаблонизатор! Уже 2 года пользуюсь! веееееезде его сую =) Он полностью соответствует всееееем моим потребностям (а это всякие серьезные штуки)! Уже 2 года без устали его мучаю =) Всем рекомендую!
07.10.2013, 13:58
Ответить

1234ru

axules, спасибо за отзыв :)
То, что не убивает нас, делает нас инвалидами.
08.10.2013, 06:54
Ответить

1234ru

С версии 0.1.45 в составных логических условиях можно использовать пробелы:

{?* a & b * } a и b {*a & b*?}

{?* a | b *} a или b {* a | b *?}
То, что не убивает нас, делает нас инвалидами.
09.10.2013, 23:26
Ответить
NO USERPIC

grytskiv

Это отличный шаблонизатор!

Перевел один свой проект на этот шаблон, все работает без проблем.
Проект с автомобильной тематики, поэтому шаблонизатор прошел довольно жесткое испытание в реальных условиях.

Адрес демонстрации скрипта Интернет магазина который использует этот шаблонизатор:
http://www.shop.brilliantcontract.net?TEMPLATES_DIRECTORY=templates/blueAndWhite/
13.10.2013, 22:07
Ответить
NO USERPIC

axules

Зашел чтоб написать коммент об ощибке =)))) но написал и сразу понял что я туууууупануууул - все работает нормалееек! Так что напишу о том что Websun рулит =))
22.10.2013, 12:47
Ответить

1234ru

вот и отлично :)
То, что не убивает нас, делает нас инвалидами.
22.10.2013, 13:20
Ответить

1234ru

С версии 0.1.46 в условных конструкциях имена констант и простых ("нециклических" - без двоеточия) переменных можно окружать пробелами (для повышения удобочитаемости):

{?* a = =CONST *} ... {* a = =CONST *?}
То, что не убивает нас, делает нас инвалидами.
13.11.2013, 17:06
Ответить

wwwplaton

Михаил, а как можно в полный путь к подключаемому шаблону добавить переменную?
К примеру делаю так:
{* +^/themes/default/cool/themes.tpl *} работает
Но мне нужно за место default подставить переменную.
11.12.2013, 07:39
Ответить

1234ru

Часть пути переменной заменить, к сожалению, нельзя. Нужно путь к шаблону составить в PHP и передать его в шаблон в виде переменной целиком:
{* + *template_path* *}
То, что не убивает нас, делает нас инвалидами.
11.12.2013, 15:40
Ответить

wwwplaton

жаль :( придется поменять структуру. Просто нужно было подгрузить шаблон каталогом выше :(
Спасибо Михаил за помощь.
11.12.2013, 16:03
Ответить

1234ru

Цитата:
Просто нужно было подгрузить шаблон каталогом выше(

В таких случаях можно так и указывать: {* + ../шаблон.tpl *}
Шаблонизатор понимает относительные пути.
То, что не убивает нас, делает нас инвалидами.
11.12.2013, 22:45
Ответить

wwwplaton

Чудо, работает!
А я ведь пробовал так. интересно почему в первый раз не вышло %) заработался :(
Спасибо Михаил :)))))
12.12.2013, 05:35
Ответить
NO USERPIC

marceting

Не получается передать данные в шаблон, путь к которому указан также через переменную.
А именно в
{* + *content* | *content_tpl* *}

Контроллер:
<?php
ini_set('pcre.backtrack_limit', 1024*1024*1024); // (см. ниже)
require("modules/websun.php");
require_once("modules/db.class.php");
require("modules/pagination.class.php");
$db  = new SafeMySQL();
$name_table             = "news";
$all_news               = $db->query("SELECT * FROM ?n",$name_table);
$all_news               = $db->numRows($all_news);
$limit                  = 10;
$offset                 = isset($_GET['offset']) ? intval($_GET['offset']) : 0;
$pageNav                = new MCMS_Page('navigation');
$pages                  = $pageNav->getLinks( $all_news, $limit, $offset, 7, 'offset' );
$data_n                 = $db->getAll("SELECT * FROM ?n LIMIT ?i,?i",$name_table,$offset,$limit);
$count_news             = sizeof($data);
$tpl                    = 'viewer/viewcontents.tpl';
$DATA["pagination"]     = $pages;
$DATA["content_tpl"]    = "short_news.tpl";
$DATA["content"]         = $data_n;
$html = websun_parse_template_path($DATA, $tpl);
echo $html;


Главный шаблон:
{* +header.tpl *}
    <div class="middle">
        <div class="tpad"></div>
        <div class="container">
            <div class="content">
                {* + *content* | *content_tpl* *}
                {* pagination *}
            </div><!-- .content-->
           
        </div><!-- .container-->

        {* +leftsidebar.tpl *}
   
    </div><!-- .middle-->
    <div class="bpad"></div>
   

</div><!-- .wrapper -->

{* +footer.tpl *}


Шаблон передающийся в переменной
{%**}
<div class="pheading"><h2>{*:title*}</h2><div style="float:left">{*:date*}</div><div style="float:right">{*:autor*}</div></div>
<div class="short_news">{*:short_news*}</div>
<div class="foot_short">{*:fulllink*}</div>
{**%}
23.12.2013, 19:23
Ответить

1234ru

А вы уверены, что $DATA['content'] не пуст? Попробуйте его распечатать.
Еще, как вариант - добавьте что-нибудь в short_news.tpl перед циклом (чтобы выводилось независимо от содержимого массива, который в шаблон передается) - тогда будет видно, подключается шаблон или нет.
То, что не убивает нас, делает нас инвалидами.
23.12.2013, 21:51
Ответить

wwwplaton

И вот он я опять к вам за помощью:)
Имеется {* + ../menu.tpl *}подключаем его и там
$DATA["menu"] = $menu;
Array
(
    [0] => Array
        (
            [id] => 1
            [www] => 44

        )

    [1] => Array
        (
            [id] => 2
            [www] => 33

        )

    [2] => Array
        (
            [id] => 3
            [www] => 65

        )


Но мне нужно что б в нужном месте показать нужный пункт.

То есть {* + ../menu.tpl *} нужно что б сработал только с menu:id=1
В другом месте для menu:id=2 и тд
04.01.2014, 22:15
Ответить

1234ru

Тогда вам нужно вынести код для одиночного элемента меню в отдельный шаблон и подключать их поочередно для каждого из элементов:

{* + *menu.0* | ../menu-item.tpl *}
{* + *menu.1* | ../menu-item.tpl *}

и т.п.
Только лучше ключами $menu сделайте уникальные идентификаторы пунктов меню.
То, что не убивает нас, делает нас инвалидами.
05.01.2014, 00:35
Ответить

wwwplaton

а в шаблоне тогда просто menu.id и menu.www ?
А то что то не получается :(
05.01.2014, 07:07
Ответить

1234ru

В шаблоне - {*id*} и {*www*}
То, что не убивает нас, делает нас инвалидами.
06.01.2014, 17:56
Ответить

wwwplaton

Спасибо!
09.01.2014, 21:34
Ответить

wwwplaton

define('BASEHREF', 'http://webew.ru/');


Как проверить существование константы?

{?*=BASEHREF*} ДА {*=BASEHREF*?}


Вот так не работает :(
12.01.2014, 00:47
Ответить

1234ru

А у меня сработало:

define('BASEHREF', 'http://webew.ru/');
$tpl = '{?*=BASEHREF*} ДА, {*=BASEHREF*} {*=BASEHREF*?}';
echo websun_parse_template(array(), $tpl);


Может быть, не самая новая версия шаблонизатора? Попробуйте обновить (ссылка на файл тут).
То, что не убивает нас, делает нас инвалидами.
14.01.2014, 14:56
Ответить

wwwplaton

Странно, как это я пропустил обновление. Только вот вот вроде обновил.
Но не помогло :(

define('BASEHREF', 'http://webew.ru/');
$tpl = '{*=BASEHREF*} - {?*=BASEHREF*} ДА, {*=BASEHREF*} {*=BASEHREF*?}';
echo websun_parse_template(array(), $tpl);


Выводит: http://webew.ru/ - ДА, http://webew.ru/
В то же время если подключать через шаблон как в примере выводит: http://webew.ru/ -

Вот такие пироги, пробуем еще так:

//define('BASEHREF', 'http://webew.ru/');
$tpl = '{*=BASEHREF*} - {?*=BASEHREF*} ДА, {*=BASEHREF*} {*=BASEHREF*?}';
echo websun_parse_template(array(), $tpl);


Выводит: - ДА,
В то же время если подключать через шаблон как в примере выводит: -




Еще пример, делаю так как мне нужно его использовать:
Теперь
define('BASEHREF', TRUE);


Выводит: 1 - ДА, 1
В то же время если подключать через шаблон как в примере выводит: 1 -

Теперь
//define('BASEHREF', TRUE);


Выводит: - ДА,
В то же время если подключать через шаблон как в примере выводит: -




14.01.2014, 22:56
Ответить

1234ru

Что-то я запутался..

define('BASEHREF', TRUE);
$tpl = '{?*=BASEHREF*} ДА {*=BASEHREF*?}';
echo websun_parse_template(array(), $tpl);


У меня выводит "ДА". А у вас?
То, что не убивает нас, делает нас инвалидами.
15.01.2014, 04:19
Ответить

wwwplaton

Выводит "ДА".

Но и так тоже выводит "ДА"

//define('BASEHREF', TRUE);
$tpl = '{?*=BASEHREF*} ДА {*=BASEHREF*?}';
echo websun_parse_template(array(), $tpl);
15.01.2014, 05:59
Ответить

wwwplaton

А вот если использовать непосредственно в файлах шаблона:

В main.tpl {?*=BASEHREF*} ДА {*=BASEHREF*?}

$tpl = 'templates/main.tpl';
echo websun_parse_template_path($DATA, $tpl);


то не чего не выводит, не зависимо существует BASEHREF или нет.

Вот что я пытался донести постом выше.
15.01.2014, 06:12
Ответить

1234ru

Теперь я вас понял.
Да, была неточность в обработке условных конструкций.
Исправлено в версии 0.1.47, ссылка на файл в статье обновлена. Попробуйте.
То, что не убивает нас, делает нас инвалидами.
15.01.2014, 15:56
Ответить

wwwplaton

Спасибо большое, теперь все отлично работает. Единственное я не совсем понял сейчас по версиям. Вчера качал:
0.1.47 - called back the possibility of spaces before variables,
         because it makes parsing of cycles harder:
         instead of [*|&..]array: we must catch [*|&..]\s*array,
         which (according to one of the tests) works ~10% slower;
         simple (non-cycle) variables and constants
         (literally how it is described in comment to previous version)
         can still work - this unofficial possibility will be left


Сегодня уже:

0.1.47 - fix in parse_if ({*?=CONST*}...{*=CONST*?} working correctly now


Вот то что было вчера, что за фикс был? А то я не совсем понял что там. Или его теперь нет?
15.01.2014, 17:02
Ответить

1234ru

Пардон, одна версия потерялась. Вы правы, 0.1.47 была, сейчас последняя - 0.1.48 (снова обновил файл в статье).
То, что не убивает нас, делает нас инвалидами.
15.01.2014, 17:37
Ответить

wwwplaton

там что то с кодировкой в кириллице, нельзя ли файлик в utf8 в архивчере? Может у меня браузер чудит.
15.01.2014, 17:41
Ответить

1234ru

Да, что-то случилось с кодировкой не то. Перезалил файл.
То, что не убивает нас, делает нас инвалидами.
15.01.2014, 19:26
Ответить
NO USERPIC

igor1985

Здравствуйте.

Подскажите, пожалуйста, есть ли возможность передачи в шаблон больше одной переменной? Поясню.

Речь идет об отрисовке многоуровневого меню. Изначально я посылаю в шаблон верхнего уровня массив пунктов+прикрепляю к этому массиву массив настроек с определенными доп. параметрами. Теперь когда у меня пошла генерация верхнего пункта и у него в ячейке подменю оказывается наличие массива подпунктов подключается вложенный шаблон. Так вот в этот вложенный шаблон я отправляю массив с подпунктами. Но в то же время мне во вложенном шаблоне нужен массив доп. настроек с верхнего уровня. Вот и не могу понять а как мне его передать во вложенный массив, ведь я уже передаю в него массив подменю.

Прошу помощи разобраться.
17.01.2014, 08:35
Ответить

1234ru

Нет, корневая переменная может быть только одна. Помимо корневой - только переменные из глобальной области видимости.

Вообще мне кажется, что необходимость иметь настройки рядом с каждым элементом меню - это не совсем правильно. Из настроек, не относящихся непосредственно к элементу меню, я себе могу представить только стилевое оформление, которое можно реализовать, используя лишь свойства блока-родителю.

Давайте разберем ваш пример подробнее. О каких конкретно настройках вы говорите?
То, что не убивает нас, делает нас инвалидами.
17.01.2014, 13:25
Ответить
NO USERPIC

igor1985

просто я не люблю писать под каждый функциональный элемент свое представление, плодиться слишком много шаблонов. Больше предпочитаю использовать один шаблон по возможности конечно у нескольких элементов. К примеру у меня в админке построение списков меню, статей, категорий визуально одинаково, отличия в ссылках и др. Для этого использую один шаблон + на входе небольшой массив параметров.

Да, спасибо, глобальные переменные цепляет {*$params.sort*}
17.01.2014, 14:17
Ответить

1234ru

igor1985
предпочитаю использовать один шаблон ... у нескольких элементов

Тогда вам нужно сделать на уровне PHP "прокладку", которая данные элементов преобразует под этот общий шаблон ("прокладка" эта будет своей для каждого случая).
То, что не убивает нас, делает нас инвалидами.
21.01.2014, 06:58
Ответить
NO USERPIC

igor1985

Абсолютно верно, именно так я и работаю. Перед рендером шаблона создаю массив параметров или как вы назвали его "прокладка", которая и видоизменяет шаблон(теги, ссылки). По мне так куда удобней добавить пару строчек кода в контроллер чем создавать новый файл с шаблоном. Конечно я не умеляю затраты на создание такого универсального шаблона и иногда куда проще пойти привычным путем и не городить буреломы в одном файле.

Спасибо вам большое за труды, шаблонизатор пашет как часы
21.01.2014, 07:49
Ответить
NO USERPIC

bimcom

А как насчет системы кэширования обработанных шаблонов?
А то сложность шаблонов растет, а с ним и время обработки.
В одном сайте в меню 1000 категорий/подкатегорий - пока обойдет все тратит 0,1с. а в некотрых местах 2 или 3 раза приходится его обходить, а если проц на хостинге занят то это время увеличивается в 2 раза :(
И это только на 1но меню, не считая остального.
15.04.2014, 08:12
Ответить
NO USERPIC

rgbeast

На мой взгляд кэширование - функция не зависящая от работы шаблонизатора. Несложно сделать обертывающую функцию websun_parse_template_path_cached($DATA, $tpl), которая работает так
1) превращает в строку имя шаблона и переданный массив, а затем делает sha1-хэш.
$myhash = sha1(serialize($DATA) . $tpl);
2) проверяет кэширован ли результат с хэшом $myhash в любом хэш-дата хранилище;
3) если да, взять из хранилища и отдать клиенту;
4) если нет, выполнить websun_parse_template_path($DATA, $tpl); результат сохранить в хранилище и отдать клиенту.

В качестве хранилища можно использовать MySQL, memcached, Tarantool и.др.
15.04.2014, 08:28
Ответить
NO USERPIC

bimcom

Ну так получится кэширование абсолютно всех страниц сайта, а хотелось бы только обработанного шаблона - то есть чтобы убрать операцию парсинга шаблона каждый раз.
Вот прям сейчас пишу вывод категорий в js скрипт - так 800 элементов выводятся 0,04с
Цитата:
{%*menu_shop*}
kats_kat[{*menu_shop:id*}]=['{*menu_shop:kat*}'];
{*menu_shop*%}

а так уже 0,08с
Цитата:
{%*menu_shop*}
kats_kat[{*menu_shop:id*}]=['{*menu_shop:kat*}'];
kats_url[{*menu_shop:id*}]=['{*menu_shop:url*}'];
{*menu_shop*%}


При том что вся логика до передачи в шаблон занимает 0,01с.
15.04.2014, 08:35
Ответить
NO USERPIC

rgbeast

Предложенный вариант как раз кэширование обработанного шаблона. Пишется обертка для websun_parse_template_path(), которая дополняет шаблонизатор кэшированием. Думаю, стоит сделать реализацию для примера и распространять как дополнение к шаблонизатору.
15.04.2014, 08:38
Ответить

1234ru

bimcom
В одном сайте в меню 1000 категорий/подкатегорий


В таком случае вряд ли стоит выгружать на страницу сразу все категории.
Даже если вы этот список сгенерируете мгновенно, HTML-код для 1000 элементов меню будет долго уходить на клиент и еще дольше обрабатываться браузером.

Для такого длинного меню лучше сделать вариант с частичным отображением - только актуальной его части, и разворачивание по отдельному AJAX-запросу. Так и проблема с долгой обработкой шаблона решится, и страница станет легче, и отрисовываться станет быстрее.
То, что не убивает нас, делает нас инвалидами.
15.04.2014, 09:11
Ответить
NO USERPIC

bimcom

С одной стороны - все верно, а с другой хотелось чтобы это меню реагировало мгновенно, попробовал генерировать весь блок текста в одну большую переменную, но и эта большая переменная передается в шаблон не быстрее, странно.
15.04.2014, 09:16
Ответить

1234ru

bimcom
попробовал генерировать весь блок текста в одну большую переменную, но и эта большая переменная передается в шаблон не быстрее, странно.
Вот это действительно странно.
В таком случае похоже, что узкое место - какое-то другое.

Можем разобраться в вашем вопросе, если вы покажете код ("большую" переменную можно приложить к сообщению в виде файла).
То, что не убивает нас, делает нас инвалидами.
15.04.2014, 14:56
Ответить

1234ru

С версии 0.1.48 основной каталог шаблонов можно задавать с использованием символа '$' — относительно корневого каталога веб-сервера:

websun_parse_template_path(
        $DATA,
        $template_path,
        '$/templates' // то же, что
    );                // "$_SERVER[DOCUMENT_ROOT]/templates"
То, что не убивает нас, делает нас инвалидами.
14.07.2014, 22:13
Ответить

1234ru

В версии 0.1.49 исправлен маленький баг при обработке циклов (имя массива обрабатывается функцией preg_quote).
То, что не убивает нас, делает нас инвалидами.
10.10.2014, 22:31
Ответить

1234ru

В версии 0.1.50 исправлен небольшой баг, связанный с определением рабочего каталога по умолчанию.
То, что не убивает нас, делает нас инвалидами.
16.04.2015, 11:57
Ответить
NO USERPIC

Asmody

Я правильно понял, что значения переменных не экранируются при выводе? Можно ли как-то добавить хотя бы htmlspecialchars?
25.04.2015, 16:45
Ответить

1234ru

Есть множество ситуаций, когда нужно значение как есть, без htmlspecialchars() (например, при выводе заполненных полей форм) или чего-либо еще. Поэтому шаблонизатор переданные значения никак не меняет.

Однако я ваше пожелание учту и в будущем, возможно, сделаю команду, которая будет строку вставлять с HTML-экранированием (типа {*var^htmlspecialchars*} вместо {*var*}).



То, что не убивает нас, делает нас инвалидами.
26.04.2015, 19:19
Ответить
NO USERPIC

Nikita22345

Автор, спасиба за скрипт. Я на основе его пишу свой и хочу спросить - возможно ли сохраняя действующий поиск по шаблону улучшить функцию
preg_replace_callback('/[for (.+)]((?>(?R)|((?![for .+])|[\/for]).+)+)[\/for]/isU', 'template::parse_cycle', $template);

При превышении определенного количества символов сайт просто перестает запускаться. Я почти не шару в регулярках, но захотел сделать подобие до пхп по тегам. Но вот проблема...
[if $pages.last]<a href='<{$url}>/<{$content}>/page_<{$pages.last}>'>Остання</a>[/if]
- идет нормально
[if $pages.last]
                <a href='<{$url}>/<{$content}>/page_<{$pages.last}>'>Остання</a>
                <a href='<{$url}>
/<{$content}>/page_<{$pages.last}>'>Остання</a>
                <a href='<{$url}>/<{$content}>/page_<{$pages.last}>'>Остання</a>
                [/if]
- работать уже не будет
03.07.2015, 23:50
Ответить

1234ru

Цитата:
При превышении определенного количества символов сайт просто перестает запускаться.

Попробуйте увеличить значение pcre.backtrack_limit (подробнее см. в статье).

Цитата:
возможно ли ... улучшить функцию

А что хотите улучшить?
То, что не убивает нас, делает нас инвалидами.
05.07.2015, 17:16
Ответить
NO USERPIC

Nikita22345

Самое интерестое то, что в этом сулчае pcre.backtrack_limit не помогает. Я, возможно, не совсем точно донес мысль - если кусок кода, который по шаблону подходит, очень большой, то сайт не запускается и в логах ошибок не фиксирует, но если его розбить на части то все будет нормально.
Я, еще до знакомства с Вашим шаблонизатором, был соорудил этот шаблон, где условие нужно задавать только в первой части
[if $id=1]...[!if $id=2]...[/if][/if]

и все вложенные понимает правильно, но данная проблема поставила в тупик.
06.07.2015, 14:04
Ответить

1234ru

Сложно сказать, не видя код, который отвечает за обработку этого места.
То, что не убивает нас, делает нас инвалидами.
06.07.2015, 14:52
Ответить

Arris

Спасибо за шаблонизатор, все отлично, но есть проблема:

В шаблоне есть ссылки вида:
<ul>
    <li>
        <a href="/something/it">it</a>
    </li>
    <li>
        <a href="/something/*/project.editteam">editteam</a>
    </li>
    <li>
        <a href="/something/*/project.settings">settings</a>
    </li>
    <li>
        <a href="/something/*/project.contribution">contrib</a>
    </li>
</ul>

Шаблонизатор убивает звездочки, превращая это в код:

<ul>
    <li>
        <a href="/something/it">it</a>
    </li>
    <li>
        <a href="/somethingproject.settings">settings</a>
    </li>
    <li>
        <a href="/something/*/project.contribution">contrib</a>
    </li>

</ul>


Что с этим делать? Отказаться от таких ссылок возможность есть, но тогда ломается презентативная логика приложения.
06.09.2015, 11:24
Ответить

1234ru

Шаблонизатор воспринимает последовательность /*...*/ как многострочный комментарий :)

Чтобы такого не было, надо звездочку экранировать: /\*.
То, что не убивает нас, делает нас инвалидами.
07.09.2015, 07:41
Ответить

Arris

Условия можно конструировать с использованием сравнения:

Как сравнить значение переменной с true или false ?
11.09.2015, 06:30
Ответить

Arris

Если мы определим:
$template_data['is_logged_in'] как true или false, а потом в шаблоне скажем:

<ul>
{?*is_logged_in='false'*}
    <li>
        <a href="/login">Вход в систему</a>
    </li>
{*is_logged_in='false'*?}

{?*is_logged_in=1*}
    <li>
        <a href="/logout">Выход (логаут)</a>
    </li>
{*is_logged_in=1*?}
</ul>


все будет работать отлично... пока мы не заменим 1 на 'true':
{?*is_logged_in='true'*}
    <li>
        <a href="/logout">Выход (логаут)</a>
    </li>
{*is_logged_in='true'*?}
</ul>


Теперь у нас показываются оба варианта если is_logged_in - FALSE... и ни одного, если соответственно TRUE!

Как быть? Я конечно оставлю =1 и =0, но...
11.09.2015, 06:40
Ответить

1234ru

Для случаев TRUE/FALSE следует применять условие без указания значения:
<ul>
{?!*is_logged_in*}
    <li>
        <a href="/login">Вход в систему</a>
    </li>
{*is_logged_in*?!}

{?*is_logged_in*}
    <li>
        <a href="/logout">Выход (логаут)</a>
    </li>
{*is_logged_in*?}
</ul>
То, что не убивает нас, делает нас инвалидами.
11.09.2015, 07:25
Ответить

Arris

Ага. Следующий вопрос. Не могу сообразить, как это сделать изящно:

В шаблоне:
<select id="auth_editprofile_gender" name="auth:editprofile:gender">
  <option value="M">кавалер</option>
  <option value="F">дама</option>
  <option value="N">существо</option>
</select>


из модели приезжает gender пользователя в виде буквы - M, F или N

Как шаблоном изящно выбрать соотв. пункт select/option? Как изящно поставить флаг selected тегу?

Я сделал так:
<select id="auth_editprofile_gender" name="auth:editprofile:gender">
  <option value="M" {?*gender='M'*}selected{*gender='M'*?}>кавалер</option>
  <option value="F" {?*gender='F'*}selected{*gender='F'*?}>дама</option>
  <option value="N" {?*gender='N'*}selected{*gender='N'*?}>существо</option>
</select>

Но мне не кажется это изящным решением. Тем более что оно не работает :(
11.09.2015, 20:55
Ответить

1234ru

Кавычки нужно двойные, а не одинарные: {?*gender="M"*}, а в остальном вы всё сделали правильно.

Возьмите инструмент для генерации полей форм: http://webew.ru/articles/5239.webew
Там же и пакет шаблонов.
То, что не убивает нас, делает нас инвалидами.
12.09.2015, 15:16
Ответить

Arris

Приветствую.

Нашел в коде комментарий:

допустимы выражения типа {*var^COUNT*}
(вернет count($var)) )


Допустима ли конструкция

{?!*var^COUNT=0*} массив не пуст {*var^COUNT=0*?!}

?
26.09.2015, 20:58
Ответить

1234ru

Да, допустима. Но в PHP для массивов выражение count($var) > 0 равносильно выражению !$var.
Так что я бы на вашем месте написал так:
{?*var*} ... {*var*?}
То, что не убивает нас, делает нас инвалидами.
27.09.2015, 15:05
Ответить

1234ru

С версии 0.1.54 для вызова из шаблона функций PHP нужно регистрировать их в переменной $WEBSUN_ALLOWED_CALLBACKS (подробнее см. соответствующий раздел статьи).
То, что не убивает нас, делает нас инвалидами.
21.10.2015, 20:46
Ответить

1234ru

В версии 0.1.55 исправлен баг обработки запятых при передаче аргументов для вызова функций.
То, что не убивает нас, делает нас инвалидами.
21.10.2015, 23:00
Ответить

bmg1

Массив из 100 000 ассотиативных массивов, добавляю в каждый из них вложеный - выходит пустота.
Ошибок не выдает - добавил
ini_set('pcre.backtrack_limit', 1024*1024*100*100);
Не помогает.
Может еще чтото надо добавить? или увеличить?
Можно как то узнать в чем проблема?!

Заранее спасибо!
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
09.11.2015, 19:56
Ответить

1234ru

ini_set('pcre.backtrack_limit', 1024*1024*100*100); - это 10 гигабайт :)
Сдается мне, PCRE строку длиной в 10 Гб обработать не сможет..

Вообще какие-то гигантские объемы у вас ... Возможно, из-за них что-то ломается.
Вам точно так много нужно? Попробуйте вместо 100 000 сделать 1000, работает ли?
Если не работает - выкладывайте шаблон и serialize() массива, будем смотреть.
То, что не убивает нас, делает нас инвалидами.
11.11.2015, 13:17
Ответить

bmg1

Памяти 32Гб, должно хватить.
Пробывал меньше.
Только когда массив уменьшается до 2433

<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet type="text/xsl" href="{*proto*}{*=DOMAIN*}/TPL/xsl-stylesheets/xml-sitemapOLD.xsl"?>
<urlset
      xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
      xmlns:xhtml="http://www.w3.org/1999/xhtml"
      xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9
            http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"
>

    <!-- created with Sitemap Generator Pro www.task.lv -->
    {%*list*}<url>
        <loc>{*proto*}{*=DOMAIN*}{*list:link*}</loc>

    {?*list:hreflang*}{%*list:hreflang*}
    <xhtml:link rel="alternate" hreflang="{*list:hreflang:lang*}" href="{*proto*}{*=DOMAIN*}{*list:hreflang:link*}"/>
    {*list:hreflang*%} {*list:hreflang*?}

    {?*list:photos*}
    {%*list:photos*}
    <image:image>
         <image:loc>{*list:photos:loc*}</image:loc>
        {?*list:photos:geo*}<image:geo_location>{*list:photos:geo*}</image:geo_location>{*list:photos:geo*?}
        {?*list:photos:title*}<image:title>{*list:photos:title*}</image:title>{*list:photos:title*?}
        {?*list:photos:caption*}<image:caption>{*list:photos:caption*}</image:caption>{*list:photos:caption*?}
    </image:image>
    {*list:photos*%}
    {*list:photos*?}
        <lastmod>{*list:lastmod*}</lastmod>
        <changefreq>{*change*}</changefreq>
        <priority>{*list:priority*}</priority>
    </url>{*list*%}

</urlset>
 


если убрать код с картинками:

 {?*list:photos*}
    {%*list:photos*}
    <image:image>
         <image:loc>{*list:photos:loc*}</image:loc>
        {?*list:photos:geo*}<image:geo_location>{*list:photos:geo*}</image:geo_location>{*list:photos:geo*?}
        {?*list:photos:title*}<image:title>{*list:photos:title*}</image:title>{*list:photos:title*?}
        {?*list:photos:caption*}<image:caption>{*list:photos:caption*}</image:caption>{*list:photos:caption*?}
    </image:image>
    {*list:photos*%}
    {*list:photos*?}



То работает до < 7440




Вот сам массив:
$numNext = count($list);
$list[$numNext]['link'] = '/' . $lang . '/' . $d['link'] . '/';
$list[$numNext]['priority'] = '1.0';
$list[$numNext]['lastmod'] = $d['date'];
$list[$numNext]['lastmod'] = date("c");
$list[$numNext]['changefreq'] = 'weekly'; //'always hourly daily weekly monthly yearly never'
$list[$numNext]['hreflang'] = array(
        array('lang' => 'ru', 'link' => '/' . $lang . '/' . $d['link-ru'] . '/'),
); //link-ru


$DATA['list'] = $list;



Пробовал менять по разному, но не меняется уже с(*10):

ini_set('pcre.backtrack_limit', 1024*1024*10);
ini_set('pcre.recursion_limit', 1024*1024*10);
 
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
12.11.2015, 22:03
Ответить

1234ru

Лучше в любом случае части для циклов вынести в отдельные шаблоны.
Даже если мы сейчас выясним источник ошибки и заставим работать так, как есть, с отдельными шаблонами будет намного быстрее.
Попробуйте это сделать. Если не заработает даже так - будем смотреть дальше.

$proto и DOMAIN советую добавлять к ссылкам в PHP, чтобы цикл было удобней завернуть в отдельный шаблон.

поправка: я смотрю, у вас немало переменных верхнего уровня, в цикле они видны не будут. Попробуйте их использовать как глобальные - {*$changefreq*} и т.п.

Шаблоны для циклов по большим массивам (больше 1000 элементов) важно хранить отдельно, в противном случае будет сильно падать производительность, т.к. циклы разворачиваются прямо в шаблон и на стадии замены переменных шаблонизатору придется искать по ооочень длинной строке.
Этого не будет происходить в случае вложенного шаблона, т.к. он обрабатывается на одной стадии с заменой переменных, отчего и получается быстрее и лучше.
То, что не убивает нас, делает нас инвалидами.
13.11.2015, 12:23
Ответить
NO USERPIC

helgab

Доброго времени суток. Вопрос о безопасности. Дело в том, что я хочу дать пользователям редактировать шаблон своего сайта из панели управления. Решил использовать Ваш шаблонизатор. Удобный, простой, будет легко сделать описание доступных для использования переменных в шаблоне.
Что нужно исправить в классе, чтобы у пользователей не было лишних возможностей? К примеру, исключить возможность обращения к глобальным переменным, типа {*$_GET.foo*} или {$title}. Хотелось бы разрешить доступ только к переменным из массива $DATA[].
Заранее спасибо.
10.11.2015, 15:31
Ответить
NO USERPIC

helgab

Закомментировал строки 373-378. Это панацея?
10.11.2015, 16:07
Ответить

1234ru

helgab
...исключить возможность обращения к глобальным переменным, типа {*$_GET.foo*} или {$title}. Хотелось бы разрешить доступ только к переменным из массива $DATA[].

Вообще требование довольно резонное. Так что я решил добавить такую возможность и выпустил очередную версию - 0.1.60 (ссылка в статье обновлена). Как пользоваться - читайте тут.

P.S. Спасибо за добрые слова о шаблонизаторе :)
То, что не убивает нас, делает нас инвалидами.
11.11.2015, 14:13
Ответить
NO USERPIC

helgab

Спасибо за оперативный ответ и обновление.
Если я отключу эту возможность, обращаться из шаблона получится только к массиву $DATA, я верно понимаю?
11.11.2015, 18:25
Ответить

1234ru

Да.
То, что не убивает нас, делает нас инвалидами.
11.11.2015, 18:39
Ответить

1234ru

В версии 0.1.70 добавлена возможность обращаться внутри циклов к порядковым номерам элементов массива с помощью конструкций ^i и ^N — при нумерации с 0 и 1 соответственно.
То, что не убивает нас, делает нас инвалидами.
24.11.2015, 06:54
Ответить
NO USERPIC

elexio

А можно подробнее насчет скорости работы/нагрузки на память? Как я понял, данный скрипт обрабатывает около 20 шаблонов в секунду. Насколько при этом увеличивается потребление памяти(по сравнению с вариантом где нет шаблонов)? Я не спец во всех этих делах, но по-моему, если использовать шаблоны - то серверу надо будет обращаться к бОльшему количеству страниц для вывода одной страницы. Оправдано ли применять данный скрипт на сайтах, на которых одновременно могут находиться 2-3 тысячи человек??
13.12.2015, 09:40
Ответить

1234ru

Цитата:
А можно подробнее насчет скорости работы/нагрузки на память?

Сильно зависит от конкретных данных и конкретных шаблонов.
Средних размеров интернет-магазин на нормальном серверном железе обрабатывает шаблоны за 25-90 мс. Памяти используется от 100 до 600 Кб.

Цитата:
если использовать шаблоны - то серверу надо будет обращаться к бОльшему количеству страниц для вывода одной страницы.

Возможно. Но для генерации страницы из исходных данных в любом случае придется выполнить какой-то код.
Показать разницу в использовании памяти может только эксперимент.

Важнее другое. Практика использования данного шаблонизатора показывает, что обычно он использует не более 20% от общего объема памяти, которое требуется для генерации страницы. Вся экономия, если и случится, будет в рамках этих 20%. На мой взгляд, обычно это не очень существенно.

Цитата:
Оправдано ли применять данный скрипт на сайтах, на которых одновременно могут находиться 2-3 тысячи человек??
Что такое "одновременно находиться"? Сколько загрузок страниц они генерируют в единицу времени?
То, что не убивает нас, делает нас инвалидами.
14.12.2015, 20:32
Ответить

1234ru

А вот, кстати, инструмент для измерений: http://webew.ru/articles/5500.webew

То, что не убивает нас, делает нас инвалидами.
15.12.2015, 19:27
Ответить
NO USERPIC

elexio

Ну 2-3 тысячи человек в минуту нагенерируют порядка 200 страниц, наверное. Да, экономия от отказа будет небольшая, тем более что шаблонизатор - полезная штука, а в проектах более 10 тысяч строк просто жизненно необходимая. Тем более такой маленький. Если проект около 15 тысяч строк, то использовать в нем любой из современных "промышленных" шаблонизаторов это все равно что летать на самолете в соседний город, вместо того, чтоб сесть в маршрутку/автобус. Эти шаблонизаторы насчитывают не менее 10 тысяч строк кода и десятки файлов.

Главное - кешировать страницы, чтобы каждый раз заново не распарсивать одно и то же, и тогда даже самый маленький шаблонизатор должен сработать на ура.
14.12.2015, 22:06
Ответить

1234ru

200 страниц в минуту - это чуть больше 3 в секунду. Думаю, этот шаблонизатор вполне справится.

Если будете кешировать, то шаблонизатору работать почти что не придется :)
Но я бы на вашем месте сначала попробовал без кеширования - возможно, скорость генерации будет вполне приемлемая.
То, что не убивает нас, делает нас инвалидами.
14.12.2015, 22:18
Ответить
NO USERPIC

elexio

Цитата:

1234ru
А вот, кстати, инструмент для измерений: http://webew.ru/articles/5500.webew


Спасибо, на этом сайте много полезного можно найти :)
15.12.2015, 19:58
Ответить
NO USERPIC

edvardpotter

Здравствуйте! Очень понравился ваш шаблонизатор - действительно легкий и удобный! У меня такой вопрос: есть шаблон "index.tpl" в котором есть верхнее меню, там есть текст "Привет {*user_name*}", если использую все в одном шаблоне то работает отлично:
<nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
            <div class="navbar-header">
              <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#navbar-collapse-01">
                <span class="sr-only">Toggle navigation</span>
              </button>
              <a class="navbar-brand" href="#">...</a>
            </div>
            <div class="collapse navbar-collapse" id="navbar-collapse-01">
              <ul class="nav navbar-nav navbar-left">
                <li><a href="...">Главная<span class="navbar-unread">1</span></a></li>
                <li class="dropdown">
                  <a href="#" class="dropdown-toggle" data-toggle="dropdown">...<b class="caret"></b></a>
                  <span class="dropdown-arrow"></span>
                  <ul class="dropdown-menu">
                    ...            
                  </ul>
                </li>
        <li class="dropdown">
                  <a href="#" class="dropdown-toggle" data-toggle="dropdown">Привет {*user_name*}<b class="caret"></b></a>
                  <span class="dropdown-arrow"></span>
                  <ul class="dropdown-menu">
                    ...            
                  </ul>
                </li>                
               </ul>                       
            </div>
</nav>

а если выношу этот кусок кода в отдельный шаблон head.tpl:
и в index.tpl пишу "{* +*?user_name* | head.tpl *}" и переменная не отображается, возможно я не правильно понял смысл этой функции, если так то поясните как сделать иначе.
26.12.2015, 22:44
Ответить

1234ru

Добрый день. {* +*?user_name* | head.tpl *} передает в шаблон переменную user_name в качестве корневой. Если хотите использовать head.tpl таким образом, вам нужно там вместо Привет {*user_name*} писать Привет {**}
({**} - корневая переменная)
То, что не убивает нас, делает нас инвалидами.
27.12.2015, 11:07
Ответить
NO USERPIC

edvardpotter

А если нужно передать несколько переменных?
27.12.2015, 13:20
Ответить

1234ru

Несколько переменных передать нельзя. В таком случае нужно передавать их родительскую переменную, и краткая запись не подходит. Нужно полную: {?*user_name*} {* +head.tpl *} {*user_name*?}, а внутри строить так же, как index.tpl
То, что не убивает нас, делает нас инвалидами.
28.12.2015, 08:55
Ответить
NO USERPIC

edvardpotter

И как сделать такую структуру шаблонов:

layout.tpl
<html>
 <head>
 ...
 </head
 <body>

   ...
  <div class"content">
    "tpl"
  <div>
   ...
 </body>
</html>


и есть какие то шаблоны которые и будут вставляться вместо "tpl" (index.tpl,add.tpl). Но и в layout.tpl должны передаваться и в "tpl"
27.12.2015, 13:20
Ответить

1234ru

Не совсем вас понял. Если вы имеете в виду, что все вложенные шаблоны должны иметь доступ к тем же переменным, что и родительский, то тогда их надо подключать самым обычным способом - без явной передачи переменной:
{* + index.tpl *}, {* + add.tpl *} и т.д.
То, что не убивает нас, делает нас инвалидами.
28.12.2015, 08:58
Ответить
NO USERPIC

edvardpotter

У меня есть сайт на symfony 2(с шаблонизатором twig), так вот там layout.tpl имеет такой вид:
<html>
 <head>
 ...
 </head
 <body>

   ...
  <div class"content">
    {{ content }}
  <div>
   ...
 </body>
</html>

Где скриптом передается какой шаблон подключить вместо "{{ content }} ". Через ваш же шаблонизатор я думаю это будет выглядеть примерно так:
ini_set('pcre.backtrack_limit', 1024 * 1024); // (см. ниже)
   
    $DATA['title']     = 'Страница';
    $DATA['docerniy_shablon']     = 'add';  //или add.tpl
    require_once 'websun.php'; // подключаем файл с шаблонизатором    
    $tpl = '^/templates/lalout.tpl'; // путь к шаблону
   
    $html = websun_parse_template_path($DATA, $tpl); // запуск шаблонизатора
   
    echo $html;

только вот не знаю как сделать вывод этой переменной в функцию подключения шаблона.
29.12.2015, 05:10
Ответить

1234ru

Подключая шаблон, можно указывать путь к нему в виде переменной:
{* + *docerniy_shablon* *}

Думаю, вам нужно именно это.
То, что не убивает нас, делает нас инвалидами.
29.12.2015, 11:33
Ответить

ewer

Здравствуйте! Скачал тут шаблонизатор, инклюдил на сайт, выдает ошибку
Parse error: syntax error, unexpected '[', expecting ')' in J:\home\game.ru\www\tpl_engine.php on line 747
ошибку нашло вот в этом
        $subobject = new $c([
                'data' => $vars,
                'templates_root' => $this->templates_root_dir,
                'predecessor' => $this,
                'no_global_vars' => $this->no_global_vars,
                'profiling' => $this->profiling,
            ]);
я так понял со скобками [ что-то и убрал их но теперь стало выдавать ошибку
Parse error: syntax error, unexpected T_DOUBLE_ARROW in J:\home\game.ru\www\tpl_engine.php on line 748
если кто знает как поправить, отпишитесь please :(
29.12.2015, 09:02
Ответить

1234ru

Это у из-за того, что PHP ниже 5.4
(разработка ведется на более новых версиях, поэтому эта ошибка была пропущена).
Исправлено, ссылка в статье обновлена - скачайте заново, должно все работать.
То, что не убивает нас, делает нас инвалидами.
29.12.2015, 11:30
Ответить

ewer

Там пропала ошибка но в 900 строке и 921 тоже было так же, по Вашему принципу дальше все встречи ([ и ]) заменил на (array( вроде бы пока ошибок нету) Спасибо =) вот файл Посмотрите там всё нормально после 900 строки? а то фиг знает))
29.12.2015, 12:12
Ответить

1234ru

Спасибо вам за содействие!
Вручную все такие места было найти непросто, а PHP 5.3 под рукой не было, так что ваши исправления очень кстати.
Код посмотрел, вроде все нормально.
В статье теперь версия с вашими исправлениями :)
То, что не убивает нас, делает нас инвалидами.
29.12.2015, 13:43
Ответить

ewer

Не за что)) Кул шаблонизатор)
29.12.2015, 14:06
Ответить
NO USERPIC

9iky6

Исправьте регулярку в find_and_parse_if:
'/{ (\?\!?) \*([^*]*)\* }(.*?){ \*\2\*\1 }/sx'

Вот так будет работать с большим объемом данных:
array('/{ (\?\!?) \*([^*]*)\* }(.*?)/sx', '/{ \*([^*]*)\* (\?\!?) }(.*?)/sx')

Передавал данные в DataTables.js, суммарно на тесте выводил около 100000 данных в массиве и эта регулярка просто не срабатывала.

А за работу спасибо, удобно, но не хватает подключения php файлов внутри шаблона, типо {* include(test.php) * }
08.01.2016, 14:13
Ответить

1234ru

Начну с конца.

Цитата:
не хватает подключения php файлов внутри шаблона, типо {* include(test.php) * }

Занесите функцию include() в список разрешенных к вызову и напишите в шаблоне {* @include("test.php") *} - вот вам и подключение файлов :)
(Хотя могут быть трудности с доступностью переменных)

На мой взгляд, однако, подключать PHP-файл прямо из шаблона - не самая лучшая практика. Рискуете запутаться, где у вас что вызывается.
Лучше все необходимые данные готовить перед вызовом шаблона.
Впрочем, на вкус и цвет товарища нет.
То, что не убивает нас, делает нас инвалидами.
11.01.2016, 14:37
Ответить

1234ru

Цитата:
Передавал данные в DataTables.js, суммарно на тесте выводил около 100000 данных в массиве и эта регулярка просто не срабатывала.

А можно пример данных и шаблон? Хочу тоже потестировать.
То, что не убивает нас, делает нас инвалидами.
11.01.2016, 14:41
Ответить

deadka

Респект создателю!

Михаил, скажите, а есть ли возможность передать в шаблон картинку в виде массива байт и дальше отобразить ее в виде картинки <img src={*БИНАРНОЕ_ПРЕДСТАВЛЕНИЕ*} />?

Чтобы на стороне php сделать что-то вроде

$var = file_get_contents($image_url);
$DATA["image"] = $var;


, то есть передать массив байт прямо в шаблон.
Через more, через less мы бредем в страну чудес...
26.01.2016, 16:50
Ответить

1234ru

Теоретически можно. Надо file_get_contents() вызвать прямо в шаблоне (добавив перед этим в список разрешенных функций):
<img src="{* @file_get_contents(*image_url*) *}">

Однако вставка бинарника прямо в текст может привести к неожиданным результатам. Там ведь есть непечатаемые символы - побьется всё... Наверное, надо сначала чем-то обрабатывать, а потом уже вставлять.
То, что не убивает нас, делает нас инвалидами.
27.01.2016, 07:36
Ответить

deadka

Мм, в предложенном варианте идет оперирование именно url'ом на картинку, а не массивом байт, содержащим изображение.

А можно ли как-то отобразить картинкой в шаблонизаторе именно переменную $DATA["image"]?, с тем что в {*image*} лежит массив байт?
Через more, через less мы бредем в страну чудес...
27.01.2016, 07:55
Ответить

1234ru

Тогда так и писать - {*image*} :)
Правда, не знаю, что у тебя из этого получится..

Или я тебя неправильно понял?
То, что не убивает нас, делает нас инвалидами.
27.01.2016, 10:33
Ответить

deadka

Понял скорее правильно, но так действительно ничего хорошего не получится ), тегу img нужна ссылка на картинку, а не массив байт. Так что вопрос снят, обошел по другому.
Через more, через less мы бредем в страну чудес...
01.02.2016, 18:45
Ответить

Arris

А как заставить шаблонизатор убирать лишние переводы строк?

Вот, допустим, такой код:
<p class="rpNav">
{%*major_sections*}
<a class="icon more-icon" href="#{*major_sections:id*}" name="{*major_sections:id*}">{*major_sections:name*}</a><br/>
{*major_sections*%}
</p>


В исходном коде страницы:
<p class="rpNav">

<a class="icon more-icon" href="#710000" name="710000">Аренда машин и оборудования без оператора; прокат бытовых изделий и предметов личного пользования</a><br/>

<a class="icon more-icon" href="#670000" name="670000">Вспомогательная деятельность в сфере финансового посредничества и страхования</a><br/>

То есть между итерируемыми строчками вставлен лишний \r\n

А если написать так:
{%*major_sections*}<a class="icon more-icon" href="#{*major_sections:id*}" name="{*major_sections:id*}">{*major_sections:name*}</a><br/>
                {*major_sections*%}

Или наоборот:
{%*major_sections*}
                <a class="icon more-icon" href="#{*major_sections:id*}" name="{*major_sections:id*}">{*major_sections:name*}</a><br/>{*major_sections*%}


То в исходном коде страницы все так как должно быть - между строками <A>..</A> лишних переводов строк нет.

Нет, я понимаю, что в принципе должно быть все равно, но ведь некрасиво же!
28.01.2016, 11:52
Ответить

1234ru

Цитата:
как заставить шаблонизатор убирать лишние переводы строк?

К сожалению, никак.
Шаблонизатор не может сам отличить лишние переводы от нелишних.

Единственный способ - это помещать перевод строки (и другие пробельные символы) внутрь многострочного комментария - /* .. */.
Цитата:
я понимаю, что в принципе должно быть все равно, но ведь некрасиво же!

Сейчас исходный код страницы в неизменно виде смотрят очень редко - все через средства разработки типа Firebug и т.п. Так что как он выровнен, большой роли не играет.
То, что не убивает нас, делает нас инвалидами.
28.01.2016, 15:51
Ответить

Arris

Спасибо
28.01.2016, 18:29
Ответить

wwwplaton

Цитата:
К сожалению, никак.
Шаблонизатор не может сам отличить лишние переводы от нелишних.

echo preg_replace ('/\s+/', ' ',  $html);

Проблема может быть только с JS и то если писать норм то все отлично :)
24.02.2016, 22:50
Ответить

1234ru

Вы так удалите все пробельные символы вообще :)
Думаю, вы имели в виду /(\n\s?)+/m.

Так или иначе, подобное действие ведет к довольно непредсказуемым последствиям и выйти оно может боком настолько, что лучше /*...*/ писать, когда требуется.
То, что не убивает нас, делает нас инвалидами.
25.02.2016, 10:11
Ответить

Arris

Ага, ок. Жаль.

Другой вопрос:

Часто в шаблоне приходится делать конструкцию:
{?*code=-1*}
код равен -1
{*code=-1*?}
{?!*code=-1*}
Код не равен -1
{*code=-1*?!}

Можно это как-нибудь соптимизировать?
28.01.2016, 18:28
Ответить

1234ru

К сожалению, пока никак...

Были разные идеи объединить два условия в одно из двух частей, а также из закрывающей скобки само условие убрать.
Но эти идеи упираются в рекурсивные регулярные выражения. Я пока решил обойтись без них.

С другой стороны, в больших шаблонах с закрывающим условием (когда не видно начала if) получается наглядней.
То, что не убивает нас, делает нас инвалидами.
28.01.2016, 19:31
Ответить

Arris

Да в принципе не напрягает ;)

Я спросил на всякий случай, вдруг какой-то способ есть, а я в описании не увидел.
28.01.2016, 22:11
Ответить

Arris

И кстати, вы не думали выложить код шаблонизатора на гитхаб? Было бы удобнее и вопросы задавать, и багрепортить...
28.01.2016, 18:29
Ответить

1234ru

Думал. Возможно, когда-нибудь выложу.
Просто шаблонизатор задумывался как вещь настолько простая, что вопросы и тем более багрепорты для него - вещь весьма редкая.
В общем, не горит пока :)
То, что не убивает нас, делает нас инвалидами.
28.01.2016, 19:36
Ответить

1234ru

Здравствуйте :)
Вы просили гитхаб? Вот https://github.com/1234ru/websun
Мне больше нравится тут, но если вам удобнее - пишите туда.
То, что не убивает нас, делает нас инвалидами.
31.08.2017, 12:55
Ответить

Arris

Отлично.

Виноват, совсем забыл про вменяемую доку :) Все с докером вожусь, хексо, блогами и прочей ересью :(
01.09.2017, 05:30
Ответить

Arris

Доброго времени суток.

А есть какая-нибудь возможность приказать шаблонизатору прекратить парсить дальнейший шаблон? Типа такого ультимативного BREAK.

Поясню нафига оно надо: страница собирается из двух шаблонов - контент вставляется в обертку (всякие там хеды, метатеги, в общем все как обычно). Но иногда при сборке контента у нас что-то идет не так и мы пишем что-то в духе "404, у нас все сломалось".

Да, можно написать что-то в духе:
{?*Error404Present*}
Все сломалось
{*Error404Present*?}
{?!*Error404Present*}
Все идет по плану... Тут наш обычный вложенный шаблон со всеми вложенными блоками итп
{*Error404Present*?!}


Но мне было бы удобнее написать что-то в духе:
{?*Error404Present*}
Все сломалось
{*^BREAK_PARSING_TEMPLATE^*}
{*Error404Present*?}


Я хочу странного, да?

25.02.2016, 01:17
Ответить

1234ru

Почему же странного? Вполне нормального вы хотите :)

Но шаблонизатор так не умеет :( Он обрабатывается не прогрессивно, а целиком, и такого понятия как "прекращение обработки" для него нет.
На мой взгляд, верная практика использования состоит в следующем: подготовка данных полностью происходит до вызова шаблонизатора и определяет в том числе то, какой шаблон будет использован, включая вложенные. Соответственно, для случая 404 просто нужен свой шаблон.

Вообще-то цивилизованное решение этой проблемы было разработать сложнее, чем кажется.
Я вам рекомендую прочесть вот эту статью: http://webew.ru/articles/5216.webew
Там более широкий круг вопросов обсуждается, чем просто текст для 404-й страницы, но если разберетесь, получите в руки удобный инструмент.
То, что не убивает нас, делает нас инвалидами.
25.02.2016, 10:20
Ответить

Arris

Столкнулся со странной ситуацией:

{?*current_sector.parent=-1*}
<a class="icon go-back" href="/sectors/">Вернуться к списку рубрик</a><br/>
{*current_sector.parent=-1*?}

{?!*current_sector.parent=-1*}
<a class="icon go-back" href="/sectors/{*parent_sector.id*}">Перейти к родительской категории «{*parent_sector.name*}»</a><br/>
{*current_sector.parent=-1*?!}


Вне зависимости от $template['current_sector']['parent'] всегда парсится второй блок - а там может быть либо -1, либо некое значение. Собственно в случае если там -1, первый блок не обрабатывается. Никогда.

То ли я ослеп к 4 утра и чего-то не вижу, то ли это баг.

Upd: я не ослеп, просто в [][] падает строка '-1', которую шаблонизатор даже не пытается приводить к числу. Это нормально что не пытается?
01.03.2016, 00:42
Ответить

Arris

Кстати, если написать

{?*current_sector.parent<0*}
<a class="icon go-back" href="/sectors/">Вернуться к списку рубрик</a><br/>
{*current_sector.parent=<0*?}

{?*current_sector.parent>0*}
<a class="icon go-back" href="/sectors/{*parent_sector.id*}">Перейти к родительской категории «{*parent_sector.name*}»</a><br/>
{*current_sector.parent>0*?}

то (несмотря на то, что в $template_data приходят строки) шаблонизатор отлично приводит значения к целым (?). Или с чем на самом деле он сравнивает строку (в переменной current_sector.parent?

На приведении типов можно очень больно наколоться.
01.03.2016, 00:47
Ответить

1234ru

Шаблонизатор понимает, какого типа величина находится в правой части сравнения (об этом ниже). Но равенство он выясняет с приведением типов, на уровне PHP применяя оператор ==, а не === (так сделано специально, чтобы не было разницы между -1 и "-1", т.к. обратное неудобно). Так что в вашем случае: «в [][] падает строка '-1', которую шаблонизатор даже не пытается приводить к числу. Это нормально что не пытается?» — как раз пытается, посредством вышеупомянутого оператора нестрогого равенства.

Для неравенств используются операторы, идентичные написанным в шаблоне.

Теперь немного подробнее о том, как шаблонизатор определяет тип величины, стоящей после знака сравнения. Если сразу открываются двойные кавычки, это интерпретируется как строка. Если вместо кавычек сразу идет числовая величина (is_numeric() возвращает TRUE), то как число. В остальных случаях — как имя переменной или константы (это если начинается с =).

Еще хочу сделать JSON — когда начинается с { или [ — но там сложно обрабатывать вложенные скобки, я пока не осилил.
То, что не убивает нас, делает нас инвалидами.
01.03.2016, 18:20
Ответить

1234ru

А у меня это поведение не воспроизводится. Вот такой код

$tpl = '{?*current_sector.parent=-1*} Минус 1 {*current_sector.parent=-1*?}

{?!*current_sector.parent=-1*} Что-то еще {*current_sector.parent=-1*?!}'
;

$data['current_sector']['parent'] = '-1';

$html = websun_parse_template($data, $tpl);

echo $html;

дает Минус 1. Попробуйте, как у вас выполнится?
То, что не убивает нас, делает нас инвалидами.
01.03.2016, 18:20
Ответить
NO USERPIC

edvardpotter

Здравствуйте!
Не подскажите почему при таком использовании:
<?php

class Controller_Portfolio extends Controller
{

    function __construct()
    {
        Session::init();
        $logged = Session::get('login');
        if($logged == true) {              
        $this->model = new Model_Portfolio();      
        $this->websun = new websun();      
        }
        else header('Location: ../login');
    }
   
    function action_index()
    {          
        $data = $this->model->get_data();      
        $this->websun->websun_parse_template_path($DATA, $tpl)
    }
}

Вылетает такие ошибки:
Warning: Missing argument 1 for websun::__construct(), called in C:\OpenServer\domains\mvc-site.ru\application\controllers\controller_portfolio.php on line 12 and defined in application\core\template.php on line 14

Fatal error: Call to undefined method websun::websun_parse_template_path() in application\controllers\controller_portfolio.php on line 20
10.03.2016, 13:24
Ответить

1234ru

Вызов в объектной форме требует передачи массива с параметрами. Это написано в комментарии в коде объявление функции __construct(), привожу тогда уж здесь:

$options - ассоциативный массив с ключами:
- data - данные
- templates_root - корневой каталог шаблонизатора
- predecessor - объект-родитель (из которого вызывается дочерний)
- no_global_vars - разрешать ли использовать в шаблонах переменные глобальной области видимости
- profiling - включать ли измерения скорости (пока не до конца отлажено)


Обязательным является только $options[data], остальные можно опустить.
То, что не убивает нас, делает нас инвалидами.
10.03.2016, 18:06
Ответить
NO USERPIC

edvardpotter

А где тогда указывать шаблон в который передаются данные?
11.03.2016, 14:27
Ответить

1234ru

Нужно получить содержимое шаблона и передавать его методу parse_template():

$W = new websun(...);
$tpl = ... // получить содержимое шаблона
$string = $W->parse_template($tpl); // в $string - результат обработки


Можете глянуть код функции websun_parse_template_path(), в ней как раз все это и делается.
То, что не убивает нас, делает нас инвалидами.
11.03.2016, 16:43
Ответить
NO USERPIC

edvardpotter

$W = new websun(...);
$tpl = ... // получить содержимое шаблона
$string = $W->parse_template($tpl); // в $string - результат обработки

Тут в websun надо передавать $data?
$W = new websun(...);
11.03.2016, 17:46
Ответить

1234ru

Да, вот так: $W = new websun(['data' => $data]);
То, что не убивает нас, делает нас инвалидами.
14.03.2016, 04:53
Ответить

wwwplaton


1234ru, как можно с вами связаться?
01.04.2016, 19:03
Ответить

1234ru

Написал вам на почту.
То, что не убивает нас, делает нас инвалидами.
02.04.2016, 12:56
Ответить

Arris

Из-за чего чаще всего возникает ошибка

Notice: Array to string conversion in /public_html/core/websun/websun.php on line 279


?
04.04.2016, 04:21
Ответить

1234ru

Из-за того, что в шаблоне написано {*var*}, где $var - массив.
При подстановке переменных в шаблон происходит их приведение к строковому типу, о чем и говорит notice.
То, что не убивает нас, делает нас инвалидами.
04.04.2016, 16:49
Ответить

wwwplaton

я так понял условие
{?*=CONSTANTS=var*} не работает :( {*=CONSTANTS=var*?}
или я опять заработался?

Разобрался, правильно будет:
{?*var==CONSTANTS*} работает! {*var==CONSTANTS*?}
13.04.2016, 09:21
Ответить

1234ru

В версии 0.1.80 добавлена проверка расширения файла шаблонизатора. По умолчанию допустимыми являются *.tpl, *.html, *.css, *.js.
То, что не убивает нас, делает нас инвалидами.
13.04.2016, 11:46
Ответить

wwwplaton

Как обычно лучше нет :)))
Михаил, есть предложение обработать ошибки вида:
Warning: file_get_contents(/.../page.tpl): failed to open stream: No such file or directory in /.../websun.php on line 837

Причина не светить полный путь к файлу (если что).
22.04.2016, 06:10
Ответить

1234ru

С другой стороны, тогда не будет понятно, какого файла не хватает.
То, что не убивает нас, делает нас инвалидами.
22.04.2016, 07:09
Ответить
NO USERPIC

MuratYMT

Предлагаю заменить
// пустая строка указывает на корневой массив
foreach ($keys as $k) {
    if (is_array($value) AND isset($value[$k]) ) $value = $value[$k];
    else { $value = NULL; break; }
}

на
// пустая строка указывает на корневой массив
foreach($keys as $k) {
    if (is_array($value) AND isset($value[$k])) {
        $value = $value[$k];
    } elseif (is_object($value)) {
        try {
            $value = $value->$k;
        } catch (\Exception $e) {
            $value = NULL;
            break;
        }
    } else {
        $value = NULL;
        break;
    }
}

для того чтобы можно было обрабатывать массив объектов
06.05.2016, 06:04
Ответить

1234ru

Можно. Только давайте сделаем немного по-другому: если указанное свойство у объекта не установлено, не будем генерировать Notice, а просто тихо вставим пустую строку (так же, как это сделано сейчас, когда не установлен ключ массива):

foreach($keys as $k) {
    if (is_array($value) AND isset($value[$k]))
        $value = $value[$k];
   
    elseif (is_object($value) AND property_exists($value, $k))
        $value = $value->$k;
   
    else {
        $value = NULL;
        break;
    }
}


Новая версия - по ссылке в статье.
То, что не убивает нас, делает нас инвалидами.
06.05.2016, 14:48
Ответить
NO USERPIC

MuratYMT

Я тоже изначально так подумал, но при таком варианте будут игнорироваться атрибуты доступные через магический метод __get. Лучше чем перехватывать исключение ничего в голову не пришло.
06.05.2016, 14:52
Ответить

1234ru

Цитата:
будут игнорироваться атрибуты доступные через магический метод __get


А реально ли нужны эти атрибуты?
То, что не убивает нас, делает нас инвалидами.
06.05.2016, 15:03
Ответить
NO USERPIC

MuratYMT

Ну многие фреймворки на них построены. Тот же yii с ActiveRecord.
06.05.2016, 15:05
Ответить

1234ru

Давайте тогда поступим так.
Если вам встретится реальная ситуация, когда это нужно (именно при обработке шаблонов) - будем думать, а пока оставим, как сейчас.
То, что не убивает нас, делает нас инвалидами.
06.05.2016, 17:12
Ответить
NO USERPIC

astashov

Скажите пожалуйста, как включить вложенность переменных в шаблоне?

В частности хочется что бы значение подставлялось соответственно идентификатору, который хранится в другой переменной.

{%*STATE*}
    <option value="{*STATE:state_id*}">{*LANG.state_{*STATE:state_id*}*}</option>
{*STATE*%}
24.05.2016, 10:55
Ответить

1234ru

К сожалению, такой возможности нет.
То, что не убивает нас, делает нас инвалидами.
24.05.2016, 10:58
Ответить
NO USERPIC

astashov

а как нибудь объединить две переменные можно будет вообще? В моем примере это склеивание. А если через ключ? Т.е.

state = array(1 => "раз", 2 => " два")


и как нибудь так....

{%*STATE*}
    <option value="{*STATE:state_id*}">{*LANG.state:{*STATE:state_id*}*}</option>
{*STATE*%}


Надеюсь мысль довел.
24.05.2016, 11:09
Ответить

1234ru

Нет, так тоже нельзя.

Оба случая упираются в рекурсивную обработку открывающих и закрывающих скобок.
Это сложно технически, и не факт, что будет достаточно быстро работать, поэтому обещать ничего не могу в этом плане.
То, что не убивает нас, делает нас инвалидами.
24.05.2016, 12:16
Ответить
NO USERPIC

astashov

Можно оформить в виде функции а-ля printf какой нибудь. И тогда не будет рекурсии. Дальше одного уровня все равно наврятли оно пригодится.
24.05.2016, 12:21
Ответить

1234ru

Там дело не в конкретной функции.
Нужно регулярное выражение {* (что угодно, кроме '*}') *} заменить на более умное, которое не закончится на первой встретившейся закрывающей скобке, Такое выражение должно быть рекурсивным.
Потом еще подстановку переменных немного подкорректировать и проверить, чтоб это все работало без ощутимого проседания производительности.

Плюс есть задумка функциям, вызываемым из шаблона, передавать массивы в виде JSON, а там тоже пляски с рекурсивными скобками будут. Все это надо продумать, чтоб не огрести потом багов.

Скажите, вам это прям сильно надо? Совсем неудобно в PHP делать?
То, что не убивает нас, делает нас инвалидами.
24.05.2016, 12:34
Ответить
NO USERPIC

astashov

Не не то что бы прямо сейчас, просто на будущее.
Искал маленький просто удобный движочек, и вот нашел :) И как бы вношу свои идеи, с чем столкнулся.
Конечно я сейчас построю временный массивчик, который уже скормлю шаблону.
Но просто, думаю что было бы удобно делать такую подстановку.

Особенно это хорошо будет сочетаться с локализацией, где айдишники и описание в разных массивах.
25.05.2016, 06:50
Ответить

1234ru

Помимо технических сложностей, меня еще останавливает сам вид синтаксической конструкции: {*LANG.state_{*STATE:state_id*}*}. Как-то много скобок и звездочек, запутаться можно.
Мне это показалось отталкивающим, так что я даже и не стал себя утруждать.
Или нормально, как вы считаете?
То, что не убивает нас, делает нас инвалидами.
25.05.2016, 17:19
Ответить
NO USERPIC

astashov

Если конструкция будет усложняться, то тогда да. А так вроде не сложно. Одна переменная включает в название другую переменную. Мне, как никсовому админу, конструкция BASH вида
VAR=$(grep $(cat /tmp/tmp.2s3NYGdgvE ) /tmp/*)

не вызывает отвращения.
Да, это не идеал, и по нормальному в скрипте надо разложить по полочкам, но если пишешь однострочник, то такое представление удобно и легко читается.

Так что судить о том хорошее такое представление или нет - я скорее всего отвечу что норм.

Только это должны быть частные включения. Не массивы, и т.д.
25.05.2016, 18:04
Ответить

1234ru

С версии 0.1.84 функциям в качестве аргументов можно передавать литералы массивов в виде JSON-нотации:

{* @implode( " ", [1,2,3] ) *}

{* @print_r( { "a":"b",  "с":[5,6,7] } ) *}


и т.п.
То, что не убивает нас, делает нас инвалидами.
02.06.2016, 10:03
Ответить

1234ru

ВНИМАНИЕ!
С версии 0.1.90 вводятся сокращенные нотации для закрывающих последовательностей циклов и условных конструкций: {%} и {?}:

(до 0.1.90): {?*a=1*} ... {*a=1*?}
( с 0.1.90): {?*a=1*} ... {?}

(до 0.1.90): {%*a*} ... {*a*%}
( с 0.1.90): {%*a*} ... {%}


Всем рекомендую: не дублировать условие в закрывающей скобке - это очень приятно!

Взяты на вооружение рекурсивные ссылки в шаблонах регулярных выражений (до которых никак не доходили руки) - (?R). Они позволяют обрабатывать парные скобки (в т.ч. сложные) любого уровня вложенности, благодаря чему и стала возможным поддержка таких сокращений.

Старая форма записи будет поддерживаться и далее (впрочем, её использование в подавляющем большинстве случаев не имеет никакого смысла).
То, что не убивает нас, делает нас инвалидами.
02.06.2016, 16:18
Ответить

1234ru

В версии 0.1.91 добавлен вариант записи условных конструкции с негативной частью:
{?*a=1*} а равно 1 {?!} а не равно 1 {?}
То, что не убивает нас, делает нас инвалидами.
03.06.2016, 15:12
Ответить
NO USERPIC

Bamper

При обработке многомерного массива в цикле возникает ошибка, но только в случае если ключ {%*products:actions*} совпадает с одним из элементов массива products:actions
{%*products*}
     {*products:name*}
     {%*products:actions*}
         {*products:actions:action*}
     {%}
{%}

в таком случае {%*products:actions*} обрабатывает только последний элемент массива

Пример массива
$products = [
         [
              'name' => 'Example',
              'actions' => [
                    'settings' => ['icon'=>'wrench', 'action'=>'settings'],
                    'price' => ['icon'=>'icon', 'action'=>'price'],
              ]
         ]
];
09.07.2016, 12:45
Ответить

1234ru

Давайте разберемся.
У меня код

$tpl = '
{%*products*}
     {*products:name*}
     {%*products:actions*}
         {*products:actions:action*}
     {%}
{%}
'
;

$products = [
    [
      'name' => 'Example',
      'actions' => [
            'settings' => ['icon'=>'wrench', 'action'=>'settings'],
            'price' => ['icon'=>'icon', 'action'=>'price'],
      ]
    ]
];

echo websun_parse_template(compact('products'), $tpl);


дает ровно вот такой результат:


     Example

         settings

         price

 


Я сходу как-то не пойму, где ошибка.
То, что не убивает нас, делает нас инвалидами.
11.07.2016, 16:05
Ответить
NO USERPIC

maks-vint

Подскажите как обновлять часть шаблона или отдельный блок в шаблоне каждую минуту?
Обновлял так без шаблонизатора
<script> setInterval(function(){$("#script").load("<?php echo basename($_SERVER['PHP_SELF']);?> #script"); }, 1000); </script>
С Шаблонизатором также делать?
11.07.2016, 11:26
Ответить

1234ru

Я вас не совсем понял.

Шаблонизатор работает на сервере, т.е. к моменту, как у вас загрузилась страница, обработка шаблона уже закончилась. Javascript в браузере про шаблонизатор знать не знает.

Для динамического обновления отдельного блока страницы вам нужно:
1) выделить этот блок в отдельный подшаблон
2) сделать специальный адрес (читай - php-файл), который будет только этот блок генерировать и отдавать
3) к этому файлу обращаться ajax-запросом, передавая его адрес функции $.load() в качестве аргумента
То, что не убивает нас, делает нас инвалидами.
11.07.2016, 16:12
Ответить
NO USERPIC

maks-vint

Я вас понял. Спасибо.
11.07.2016, 16:30
Ответить
NO USERPIC

NameAlfa

Привет!

Ошибка: Parse error: syntax error, unexpected '[' in /home/test/websun.php on line 294

Но там только строчка
$template = preg_replace('/ \\/\* (.*?) \*\\/ /sx', '', $template); /**ПЕРЕПИСАТЬ ПО JEFFREY FRIEDL'У !!!**/

К сожалению, пхп только 5.3.27 только доступен для этого древнего проекта, куда Ваш шаблонизатор встроен.

Как можно исправить?
29.07.2016, 05:02
Ответить

1234ru

Это так PHP ниже 5.4 ломается об новую декларацию массива - [] вместо array().
Сделал 5.3-friendly. Ссылка в статье обновлена - скачайте, попробуйте.
То, что не убивает нас, делает нас инвалидами.
29.07.2016, 13:52
Ответить
NO USERPIC

NameAlfa

Спасибо! Работает. Вопрос: с версии 1.5 многое изменилось касательно вывода переменных?
29.07.2016, 20:05
Ответить

1234ru

Нет, практически ничего не изменилось.
Разве что в циклах добавились конструкции :^N и :^i - порядковые номера элементов массива, начиная с 0 и 1 соответственно.
То, что не убивает нас, делает нас инвалидами.
01.08.2016, 22:12
Ответить
NO USERPIC

astashov

Нашел одну фичу. В блоке else не работает обработка вложенных условий. Т.е. если внутри then вложить условие, то оно работает, а вот если в блок else, то нет. Выводится как есть, даже не обробатываясь и не удаляясь.
04.08.2016, 09:40
Ответить

1234ru

И правда. Как-то я забыл второй части if рекурсивную обработку добавить :o

Исправил. В тексте статьи обновленная ссылка - попробуйте.
То, что не убивает нас, делает нас инвалидами.
04.08.2016, 10:13
Ответить
NO USERPIC

astashov

Отлично. Работает. Спасибо!
05.08.2016, 13:06
Ответить

Arris

Вечер добрый.

Регулярно приходится писать в шаблоне:
{?*is_state*}
Статус:     {*is_state*}
{*is_state*?}


Можно ли это как-то оптимизировать?
(я по-прежнему использую старую нотацию в шаблонах... привык)
20.09.2016, 20:32
Ответить

1234ru

Кроме как {?*is_state*} Статус: {*is_state*} {?} посоветовать ничего не могу.
Но вы, похоже, итак про это знаете :)
То, что не убивает нас, делает нас инвалидами.
20.09.2016, 22:20
Ответить

1234ru

В версии 0.1.94 добавлена возможность вызывать методы классов, как статические, так и методы экземпляров объектов:

$DATA['somedate'] = date_create(); // создан объект класса DateTime


{* @*somedate*->format("d.m.Y") *} - вызов метода экземпляра объекта
   
{* SomeClass::someMethod(*somedate*) *} - вызов статического метода класса


Регистрация в списке разрешенных к вызову:
$WEBSUN_ALLOWED_CALLBACKS = [
    'DateTime::format',
    'SomeClass::someMethod',
]
:
То, что не убивает нас, делает нас инвалидами.
06.10.2016, 02:03
Ответить

bmg1

:( после смены версии с 1.5 на последнию 1.9, перестали работать готовые шаблоны.
в логах апача ошибок нет, на экране тоже(сервер ничего не возвращает в броузер)
броузер выдает: "Соединение было сброшено"

Чтото сильно изменилось?

Как определить в чем и почему ошибка?

С Уважением,
Владимир
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
18.10.2016, 09:23
Ответить

1234ru

Ого! Ну давайте разбираться. От вас мне требуется:

1. Версии PHP и PCRE (ее можно посмотреть в phpinfo() )
2. Шаблон какой-нибудь.
3. Данные, которые передаются шаблонизатору (например, в виде json_encode() ).

Честно, проверяю на работающем проекте каждую версию (у меня там PHP 5.4). Всё гладко.
То, что не убивает нас, делает нас инвалидами.
18.10.2016, 10:20
Ответить

bmg1

1) php PHP 5.6.25 + PCRE Library Version 8.38 2015-11-23 , pcre.backtrack_limit=1000000, pcre.recursion_limit=100000
2) сложный - циклы, проверки вложенность, инклюде файлов - не хотелось бы показывать - инранет приложение.
3) данные - немного - но вложенность 2-3уровня - не хотелось бы показывать - инранет приложение.

* Как вообще возможно без ошибок завершение и не возвращает ничего функция websun_parse_template_path

** - Подскажите как выходить из таких непонятнок
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
18.10.2016, 13:09
Ответить

bmg1

Блинский...

Уменьшал код что бы оттпарвить а проверку, и нашел в чем косяк был:
       <!-- {?*table.data::^KEY="id"*}this ID!{*table.data::^KEY="id"*{*var*?}-->
 

* Закоментированная строка - которая до 1.5версии не отрабатывала :(

Всем спасибо!
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
18.10.2016, 13:32
Ответить

bmg1

Извиняюсь нашел где проблема:

        {%*list:*}
            <div class="textfield" >
                <h4 style="text-align: left;">{*list::^KEY*}</h4>
                <div class="tabs">
                    <ul>
                      {%*list::*} <li><a href="#tabs-{*list::^KEY*}-{*list:::^KEY*}">{*list:::^KEY*}</a></li>{*list::*%}
                    </ul>

                    {%*list::*}
                    <div id="tabs-{*list::^KEY*}-{*list:::^KEY*}">
                        {%*list:::*}
                        {* +*list::::* | form2.fields.tpl.html *}
                        {*list:::*%}
                        <div style="clear: both;"></div>
                    </div>
                    {*list::*%}
                </div>
            </div>

        {*list:*%}


list: {"eee":{"rrrr2":{"tttt3":{"uuuu4":"STOP"}}}}

/* или даже когда  */
list:null
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
18.10.2016, 13:46
Ответить

1234ru

Если вашу конструкцию обернуть в {%*list*} ... {*list*%}, то у меня работает (с поправкой на то, что я убрал вызов вложенного шаблона, т.к. им не располагаю).
Что и понятно: если взять так, как есть, то циклические конструкции (двоеточия) употреблены вне цикла, точнее, не хватает его верхнего уровня.

При list=null будет, очевидно, пустота, т.к. цикл не выполнится ни разу, а всё содержимое внутри цикла.

А вообще я вам советую переходить на сокращенный вариант закрывающих скобок циклов и if'ов - {%} и {?}, это ж и есть главное отличие между 1.50 и 1.90! И про негативную часть if'ов тоже не забудьте :)
То, что не убивает нас, делает нас инвалидами.
18.10.2016, 14:50
Ответить

bmg1

точнее вот две забытые строчки - и ничего не работает:

 {%*list*}

        {?*list:^KEY="fieldset"*}
        {%*list*}
            <div class="textfield" >
                <h4 style="text-align: left;">{*list::^KEY*}</h4>
                <div class="tabs">
                    <ul>
                      {%*list::*} <li><a href="#tabs-{*list::^KEY*}-{*list:::^KEY*}">{*list:::^KEY*}</a></li>{*list::*%}
                    </ul>

                    {%*list::*}
                    <div id="tabs-{*list::^KEY*}-{*list:::^KEY*}">
                        {%*list:::*}
                               ууууу
                        {*list:::*%}
                        <div style="clear: both;"></div>
                    </div>
                    {*list::*%}
                </div>
            </div>

        {*list*%}
        {*list:^KEY="fieldset"*?}



        {*list*%}


* Это старый код, - переделывать - что бы еще 2года стояло :)
** или поддержка старых "окончаний" не поддерживается в 1.9?
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
18.10.2016, 15:04
Ответить

1234ru

1. В третьей значимой строке не хватает уровня вложенности: {*list*}, а {*list:*}
2. В массиве, который используется для примера, нужно "eee" заменить на "fieldset" (в противном случае ложно условие внутри цикла, и в результате пустота).

Если это подкорректировать, то у меня работает.

Попробуйте тоже так проделать.
Если не будет работать, значит, у нас с вами работает по-разному, надо искать, где ломается у вас.
Для этого уберите внутренность цикла совсем (вернее, поставьте туда что-то примитивное типа единицы) и добавляйте обратно постепенно, пока не воспроизведется ошибка.
То, что не убивает нас, делает нас инвалидами.
18.10.2016, 17:29
Ответить

bmg1

Всеравно не работает.
:(
уменьшил объем данных работает.
данных не так много - 300-500 ключей со строками в массиве

непонимаю куда рыть - на серервере ошибок нет, а апач ничего не возвращает - сервер aborted.
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
19.10.2016, 09:27
Ответить

1234ru

Ага. То есть, неполадки начинаются, когда массив достигает определенных размеров?

А быстро ли заканчивается выполнение, когда сервер aborted? И как это вообще выглядит?
То, что не убивает нас, делает нас инвалидами.
19.10.2016, 11:15
Ответить

bmg1

С размером массива, то же невсе четко,
зависит от отработки этого массива и кода шаблона
- убираешь несколько циклов или уменьшаешь строки циклах, или обрезаешь шаблон.

-- вроде похожий(больших объемах данных = итерраций) баг есть в smarty - там он решается include.
-- но у нас на порядок меньше данных: 3-4 массива с 15-20 массивами, в каждом из которых 7-12 строк длиной не более 200символов.
-- заметил еще что если нет уникода - кириллица к примеру - то позволяет больше данных отрабатывать.


Не отрабатывает за 10-15секунд.

Выглядит так:
с 1.5 http://www.task.lv/webew/web1.png
http://www.task.lv/webew/web1.png

c 1.9 http://www.task.lv/webew/web2.png
с 1.5 http://www.task.lv/webew/web2.png

Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
19.10.2016, 11:38
Ответить

1234ru

10 секунд для таких объемов - это очень долго.
У меня XML на несколько тысяч записей генерируется быстрее, и там у каждой записи есть тоже своя структура.

А нет ли у вас там вызова функций из шаблона?
То, что не убивает нас, делает нас инвалидами.
19.10.2016, 12:06
Ответить

bmg1

Так вот и странно.
Есть проекты где sitemap генериться, с вложеностями.
Но вот с 1.9 - жопа началась - а главное не понятно куда рыть в какой момент происходит, на какой точке в коде останавливается и выдает Aborted
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
20.10.2016, 09:36
Ответить

bmg1

И даже set_error_handler не срабатывает.
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
20.10.2016, 09:43
Ответить

bmg1

Нашел проявление ошибки, в общем логе апача:
[Thu Oct 20 12:49:31 2016] [notice] Parent: child process exited with status 3221225725 -- Restarting.

Но что с этим делать?

===========================================
Нашел ответ у гугла:
В httpd.conf, для apache Windows вписать после загрузки модулей
<IfModule mpm_winnt_module>
   ThreadStackSize 8888888
</IfModule>

Тут написано подробнее о том что то такое:
http://www.remoteshaman.com/unix/common/about-stack-size-in-unix-like

На продакшен тоже заработало, видимо там из-за глюка в шаблоне не работало

Всем спасибо за помощь!
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
20.10.2016, 09:50
Ответить

1234ru

Цитата:
продакшен тоже заработало, видимо там из-за глюка в шаблоне не работало


Это вы какой глюк имеете в виду?
То, что не убивает нас, делает нас инвалидами.
20.10.2016, 10:28
Ответить

bmg1

Этот:
    <!-- {?*table.data::^KEY="id"*}this ID!{*table.data::^KEY="id"*{*var*?}-->


в этом сообщении: http://webew.ru/articles/3609.webew#5696
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
20.10.2016, 10:54
Ответить

1234ru

А вы ThreadStackSize на продакшене повышали?
То, что не убивает нас, делает нас инвалидами.
21.10.2016, 06:08
Ответить

bmg1

нет.
Там Линукс
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
21.10.2016, 07:29
Ответить
NO USERPIC

rgbeast

Попробуйте добавить в PHP
error_reporting(E_ALL);


Вдруг такм undefined function или что-то подобное.
18.10.2016, 11:29
Ответить

bmg1

Пробовал.
Стояли звери Около двери, В них стреляли, Они умирали. (с) А. и Б. Стругацкие
18.10.2016, 12:46
Ответить

wwwplaton

Кто то пробовал создавать синтаксис для последней версии в нотепад++?
Хотелось бы что б в коде можно было подсветить от {%*MAIN*} до {%} как DIV
{%*MAIN*}
    {?*MAIN:id=0*}
        <div>
            {*MAIN:id*}
        </div>
    {?}
{%}




P.S. Почему нельзя вставить картинку с другого ресурса :(
02.12.2016, 17:21
Ответить

1234ru

Да, были мысли добавить подсветку синтаксиса, но руки не дошли.

Надо разбираться, как это делается. Думаю, несложно. Основная проблема - сделать так, чтобы HTML-код тоже подсвечивался (обычно ведь шаблоны делаются для HTML).
Займусь через некоторое время. Если в течение пары недель не будет - пните (лучше на почту - у вас есть).
То, что не убивает нас, делает нас инвалидами.
06.12.2016, 10:18
Ответить

ewer

Здравствуйте! Скажите пожалуйся можно ли сократить имена функций "websun_parse_template_patch" и "websun_parse_template" ?? На допустим такие "parse_patch" и "parse" ?
06.12.2016, 06:34
Ответить

1234ru

Только не patch (заплатка), а path (путь).

Вам нужно использовать псевдонимы функций:

use function websun_parse_template as parse;
use function websun_parse_template_path as parse_path;

Надеюсь, у вас PHP версии 5.6 или выше. Если нет - пишите, расскажу, как похожего эффекта добиться для более ранних версий.
То, что не убивает нас, делает нас инвалидами.
06.12.2016, 10:26
Ответить

ewer

"patch" опечатка)) У меня PHP Version 5.3.13
Без псевдонимов нельзя? Я просто их у себя переименовал
06.12.2016, 11:17
Ответить

1234ru

Переименовывать неудобно, потому что это придется делать каждый раз, когда вы обновляете код (хоть это и нечасто). Лучше сделать функции-обертки. Попробуйте вот так:

function parse() { return call_user_func_array("websun_parse_template", func_get_args()); }
function parse_path() { return call_user_func_array("websun_parse_template_path", func_get_args()); }
То, что не убивает нас, делает нас инвалидами.
06.12.2016, 13:57
Ответить

ewer

Спасибо! Мне проще переименовать но за пример спасибо! Учту!
06.12.2016, 18:17
Ответить

ewer

echo websun_parse_template_path($page,'/tpl/site/head.tpl');
почему-то не фурычит хотя путь и имя файла верны
Warning: file_get_contents(/tpl/site/head.tpl) [function.file-get-contents]: failed to open stream: No such file or directory in J:\home\well-played.ru\www\engine\classes\tpl.php on line 968
06.12.2016, 19:40
Ответить

1234ru

У вас путь начинается со слэша, и файловая система воспринимает его как абсолютный.
Видимо, вам нужен путь относительно каталога веб-сервера. Он должен начинаться с $. Попробуйте $/tpl/site/head.tpl
То, что не убивает нас, делает нас инвалидами.
07.12.2016, 16:06
Ответить
NO USERPIC

Bamper

Добрый день! очень не хватает при использовании if-else обработки результатов функций
пример:
{?*@in_array(*id*, *data*)*}
    checked
{?}
09.12.2016, 12:04
Ответить

1234ru

Да, были мысли такое реализовать.

Постараюсь в ближайшее время сделать. Напишу тогда.
То, что не убивает нас, делает нас инвалидами.
12.12.2016, 07:30
Ответить

wwwplaton

Может тогда еще кое что? Сейчас убегаю на работу, а вечером выражу свою мысль с примером. Так как я не нашел способа сделать такое средствами шаблонизатора.
12.12.2016, 07:36
Ответить

1234ru

Давайте, интересно.
То, что не убивает нас, делает нас инвалидами.
12.12.2016, 09:38
Ответить

wwwplaton

Даю :))
Так как мне жалуются что я плохо объясняю суть дела, то я постарался показать наглядно.

История началась с того что есть некая информация которую нужно вывести в таблице. И тут стал вопрос о том что нужно выводить только те данные которые есть, ведь зачем показывать пустые столбцы и строки. Долго мучаясь с помощью данного шаблонизатора я понял что он для этого еще не адаптирован, и под шумок решил предложить дополнить его таким функционалом.

Покажу на простом примере:
test.php
<?
# http://webew.ru/articles/3609.webew
# by wwwplaton

if(isset($_GET['test_1'])){
$DATA['TEST'] = [
    [
            'name' => 'Amstrong',
            'score' => 142,
            'other' => [
                    'ping' => 6,
                    'deaths' => 3,
                    'pid' => 482736739
                ]

    ],

    [
            'name' => 'Diez',
            'score' => 120,
            'other' => [
                    'ping' => 2,
                    'deaths' => 16,
                    'pid' => 482740107
                ]

    ],

    [
            'name' => '=FBI=',
            'score' => 119,
            'other' => [
                    'ping' => 68,
                    'deaths' => 0,      # не выведет так как {?*TEST:other.deaths*} отреагирует на 0 как FALSE
                    'pid' => 482737790
                ]

    ]


];

}else if(isset($_GET['test_2'])){


$DATA['TEST'] = [
    [
            'name' => 'Fedot',
            'score' => 7,
            'other' => [
                    'time' => '00:04:18'
                ]

    ],

    [
            'name' => 'den4ik',
            'score' => 6,
            'other' => [
                    'time' => '00:08:33'
                ]

    ],

    [
            'name' => 'LeON',
            'score' => 0,   # не выведет так как {?*TEST:score*} отреагирует на 0 как FALSE
            'other' => [
                    'time' => '00:44:32'
                ]

    ]
    ,

    [
            'name' => '',   # бывает и такое тоже FALSE
            'score' => '',  # так же, но хотелось бы что б выводило если есть ключ score
                            # и не важно есть в нем данные или нет главное есть ключ,
                            # в одном нет данных но вдругом будет
                            # это хорошо видно в примере с other обоих массивов
           
            'other' => [
                    'time' => '00:53:12'
                ]

    ]
       
];

}else{
    $DATA['TEST_MENU'] = TRUE;
}



require_once 'websun.php'; // подключаем файл с шаблонизатором

$tpl = 'test.tpl'; // путь к шаблону

$html = websun_parse_template_path($DATA, $tpl); // запуск шаблонизатора

echo $html; // получили обработанный шаблон, отдаем клиенту результат


 


и test.tpl
/* http://webew.ru/articles/3609.webew */
/* by wwwplaton */
<html>
    <head>
        <style>
          table{
            margin: 50px 0;
            text-align: left;
            border-collapse: separate;
            border: 1px solid #ddd;
            border-spacing: 10px;
            border-radius: 3px;
            background: #fdfdfd;
            font-size: 14px;
            width: auto;
          }
          td,th{
            border: 1px solid #ddd;
            padding: 5px;
            border-radius: 3px;
          }
          th{
            background: #E4E4E4;
          }
          caption{
            font-style: italic;
            text-align: right;
            color: #547901;
          }
        </style>   
    </head>
    <body>

   
   
{?*TEST_MENU*}<a href="?test_1">ТЕСТ 1</a> | <a href="?test_2">ТЕСТ 2</a>   {?!} <a href="?">Назад</a>{?}
   
        /* Таблица */
        {?*TEST*}
        <table>
            <thead>
                <tr>
                    <td><b># </b></td>

                    {?*TEST.0.name.*}<td><b>Ник</b></td>         {?}
                    {?*TEST.0.score.*}<td><b>Счет</b></td>          {?}
                    {?*TEST.0.other.time.*}<td><b>Время</b></td>       {?}
                    {?*TEST.0.other.ping.*}<td><b>Пинг</b></td>         {?}
                    {?*TEST.0.other.deaths.*}<td><b>Смертей</b></td>     {?}
                    {?*TEST.0.other.pid.*}<td><b>PID</b></td>           {?}
                </tr>
            </thead>
            <tbody>
            {%*TEST*}
                <tr>
                    <td>{*TEST:^N*}</td>
                    {?*TEST:name*}<td >{*TEST:name*}</td>           {?}
                    {?*TEST:score*}<td>{*TEST:score*}</td>              {?}
                    {?*TEST:other.time*}<td>{*TEST:other.time*}</td>        {?}
                    {?*TEST:other.ping*}<td>{*TEST:other.ping*}</td>        {?}
                    {?*TEST:other.deaths*}<td>{*TEST:other.deaths*}</td>    {?}
                    {?*TEST:other.pid*}<td>{*TEST:other.pid*}</td>          {?}

                   
                </tr>
            {%}
            </tbody>
            </table>
        {?}



    </body>
</html>


Если посмотреть внимательно на результат то видно как сдвигаются TD если в данных результат обычное число 0
TEST 1

TEST 2


Чего хотелось? Проверять как то в массиве что есть какой то score или что то в other и получить результат с примером TEST 1 вот так:


P.S. Я думаю что донес мысль, сильно не пинать. Сам расскажу если есть вопросы.
P.S.S. Это очень нужно и полезно для динамических данных, когда ты не в силах предугадать все.

12.12.2016, 17:54
Ответить

1234ru

То есть, вам нужно знать, есть ли в массиве элемент с данным ключом. Я правильно понял?
То, что не убивает нас, делает нас инвалидами.
14.12.2016, 09:51
Ответить

wwwplaton

Да, нужна возможность проверки ключа. Так будет удобнее делать условия для зпголовков. И вот все-таки я думаю что если if на 0 говорит false то в некоторых случаях теряется логика как раз и за того что это просто 0. А вот если в ключе не чего нет но ключ есть то в if будет правильно false.
14.12.2016, 10:12
Ответить

1234ru

Понял.
Это логичней всего делать с помощью if на основе результата функции, о чем выше писал ewer.
В ближайшее время попробую реализовать.
То, что не убивает нас, делает нас инвалидами.
14.12.2016, 15:56
Ответить

wwwplaton

а применить ^KEY в многомерном массиве как то можно будет?
14.12.2016, 17:29
Ответить

1234ru

Ну да... А какие с этим проблемы? И сейчас ведь можно :)
То, что не убивает нас, делает нас инвалидами.
16.12.2016, 09:23
Ответить

wwwplaton

Из примера выше как получить ключи от other? Вообше пример вывода ключей всего массива хотел увидеть что бы понять как это можно :) Потому что максимум на что меня хватило:
{%*TEST*}
    <br>{*TEST:^KEY*}
{%} 



Хотя спустя часик методом тыка вот это:
{%*TEST*}
<h4>{*TEST:^KEY*}</h4>
    {%*TEST:other*}
        <br>{*TEST:other:^KEY*}
    {%}
{%} 


И еще часик:

{%*TEST*}
    <h4>{*TEST:^KEY*}</h4>
    {?*TEST.0.other.^KEY="ping"*}<br> пинг в первом ключе - {*TEST.0.other.ping*}{?} /* Вот тут я впал в ступор, if в таком виде не работает */
        {%*TEST:other*}
            {?*TEST:other:^KEY="ping"*}<br> это пинг - {*TEST:other.ping*}{?}
        {%}
{%} 


Еще немного поиграл с кавычками:
{%*TEST*}
    <h4>{*TEST:^KEY*}</h4>
    {?*TEST.0.other.^KEY=ping*}<br> пинг в первом ключе - {*TEST.0.other.ping*}{?}
        {%*TEST:other*}
            {?*TEST:other:^KEY=ping*}<br> это пинг - {*TEST:other.ping*}{?} /* Поубирал кавычки теперь то работает а это нет, все. */
        {%}
    {?*TEST:other.^KEY=ping*}<br> или так пинг - {*TEST:other.ping*}{?}
{%}


А проверить score как ключ не удается.
16.12.2016, 10:23
Ответить

1234ru

Цитата:
как получить ключи от other?

Не совсем понял. array_keys($TEST['other']) интересует?
То, что не убивает нас, делает нас инвалидами.
16.12.2016, 15:26
Ответить

wwwplaton

Если брать мой пример выше то получается что это:
array_keys($DATA['TEST'][0]['other'])

Хотя что то у меня получилось из сообщения выше
Я очень много мучелся но так и не понял как бы мне применить ^KEY

Но вот как определить есть ли в массиве ключ score вообще не смог сообразить.
16.12.2016, 15:47
Ответить

1234ru

Цитата:
как определить есть ли в массиве ключ score вообще не смог сообразить

Думаю, подойдет isset($DATA['TEST'][0]['other']['score']). Не?
То, что не убивает нас, делает нас инвалидами.
16.12.2016, 17:13
Ответить

wwwplaton

В таком случае для score isset($DATA['TEST'][0]['score'])
Но это в php, у меня же вопрос как это сделать в шаблоне?
{?*TEST:score*}если в {*TEST:score*} будет 0 то сработает как FALSE не так ли? {?}
16.12.2016, 17:24
Ответить

1234ru

В шаблоне будет что-то типа {?*@isset(*:score*) *} ... {?}, просто сейчас еще не готово.
Мне нужно было убедиться, что требуется именно это :)
То, что не убивает нас, делает нас инвалидами.
19.12.2016, 08:57
Ответить
NO USERPIC

Bamper

да, то что нужно
19.12.2016, 10:22
Ответить

1234ru

Рабочий вариант получился вот таким:
{%*TEST*}
  {?* @array_key_exists("score", *TEST:*) *} ... {?}
{%}

Вышло немного посложнее, чем с isset (с ней возникли определенные трудности), но ведь и случай у вас нетипичный ;)
То, что не убивает нас, делает нас инвалидами.
19.12.2016, 16:39
Ответить

1234ru

Сделано!
Ссылка на новую версию - в тексте статьи.

Будет глючить, если среди аргументов функций будут строки, содержащие символы из набора |&=><. Это специальные символы if'ов. Чтобы научить шаблонизатор правильно такое обрабатывать, надо хорошенько переписать пару мест, а мне, честно скажу, сейчас это было делать лень :)
В основном, потому. что это вряд ли сыграет роль.
Если кто-то все же с этим столкнется - пишите, будем исправлять.
То, что не убивает нас, делает нас инвалидами.
19.12.2016, 16:31
Ответить

wwwplaton

Мне кажется что ссылка не изменилась в статье.
22.12.2016, 16:50
Ответить

1234ru

Да, действительно, ссылка почему-то устаревшая осталась.
Сейчас исправил и проверил - точно актуальная.
То, что не убивает нас, делает нас инвалидами.
23.12.2016, 08:11
Ответить

wwwplaton

отлично, но при первом же тесте все провалено.
Как использовать это вне цикла?
{%*TEST*}
  {?* @array_key_exists("score", *TEST:*) *}Работает{?}
  {?* @array_key_exists("pid", *TEST:other*) *}Работает{?}
{%}
{?* @array_key_exists("score", *TEST:*) *}Не работает :({?} #Warning: array_key_exists() expects parameter 2 to be array, null given in .......  on line 827
23.12.2016, 20:12
Ответить

1234ru

Не совсем понял ваш вопрос.
Вне цикла использовать так же, как и внутри, только надо писать TEST без двоеточия после - как раз по той причине, что это вне цикла.
То, что не убивает нас, делает нас инвалидами.
26.12.2016, 05:54
Ответить

wwwplaton

Ну да, я тут методом тыка натыкал на это:
{?* @array_key_exists("score", *TEST.0*) *}Вот так работает{?}
26.12.2016, 10:53
Ответить

ewer

Что-то
{*+*page*.tpl*}
такая конструкция не работает :( Данные приходят, название верно но файл не подгружает(
28.12.2016, 08:06
Ответить

1234ru

Можно только {* +*page* *}.
То, что не убивает нас, делает нас инвалидами.
28.12.2016, 16:00
Ответить

ewer

Амм написано ведь

Путь к шаблону может также передаваться в переменной. Например, если записать путь к шаблону меню в $DATA['menu_template'], то подключение его примет вид
{* + *menu_template* *}
28.12.2016, 18:48
Ответить

1234ru

Ну да.
А вы хотели передать часть пути в переменной, а расширение - отдельно (если я вас правильно понял). Такое желание понятно, но, к сожалению, так нельзя.
{*+*page* *} - можно
{*+*page*.tpl*} - нельзя
То, что не убивает нас, делает нас инвалидами.
29.12.2016, 09:59
Ответить

ewer

:((
29.12.2016, 20:29
Ответить

ewer

Что-то сайт по полчаса грузится ((
30.12.2016, 09:27
Ответить

1234ru

Конкретно эта страница очень объемная, т.к. много комментариев (около 400 сейчас), и многие из них длинные.
Сайт как написали 8 лет назад, так он и работает. Переписать надо много уже давно, но все никак руки не доходят. Так и живем :)
То, что не убивает нас, делает нас инвалидами.
30.12.2016, 10:43
Ответить

ewer

O_o 8 лет? Норм)
30.12.2016, 17:31
Ответить

wwwplaton

Мне кажется это не правильно работает.
{%*menu*}
    {*name*} /* Работает */
{%}

{* +*%menu* | menu-item.tpl *}

то в menu-item.tpl {*name*} не работает
05.01.2017, 00:13
Ответить

1234ru

Должно работать. Это часто используется, я бы заметил неполадки.

Попробуйте в menu-item.tpl написать просто "1", подключение шаблона по циклу тогда должно дать столько единиц, сколько в массиве элементов. Если единиц нет, значит, либо массив пустой, либо ошибка допущена при написании вызова вложенного шаблона.
То, что не убивает нас, делает нас инвалидами.
09.01.2017, 06:59
Ответить

wwwplaton

Да я прежде чем написать всякое перепроверил, сам шаблон подгружается и отрабатывает все как надо. Я вот что думаю что он name ищет в массиве menu которого там нет. Откопал версии 0.1.48 и 0.1.80 (из тех что у меня на виду были, так их больше :)) там та же беда.
09.01.2017, 19:34
Ответить

1234ru

При такой записи, как у вас выше, он name ищет в каждом из элементов menu.
Попробуйте в menu-item.tpl добавить <pre>{* @print_r(**, 1) *}</pre> - увидите, какой массив этому шаблону передается.
То, что не убивает нас, делает нас инвалидами.
10.01.2017, 12:49
Ответить

wwwplaton

Ну да если шаблон подгружать то там только ключи из массива menu.
Было бы не страшно, но у меня тут дерево и шаблон подгружает сам себя когда нужно. Есть еще варианты?
10.01.2017, 16:46
Ответить

1234ru

Не совсем понял. Покажите структуру массива.
То, что не убивает нас, делает нас инвалидами.
10.01.2017, 20:24
Ответить

wwwplaton

Отобразил всю суть проблемы на примере, все в одном архиве. http://webew.ru/f/PkYnAygn.tgz
11.01.2017, 00:39
Ответить

1234ru

Ну не знаю. Похоже, у меня сработало как надо:

То, что не убивает нас, делает нас инвалидами.
11.01.2017, 02:44
Ответить

wwwplaton

Я в панике, это выводит в comment.tpl а в li.tpl нет.
http://wwwplaton.ru/webew/
11.01.2017, 10:06
Ответить

1234ru

Я в массиве comments не вижу ключа reply как такового. Видимо, поэтому в скобках пустота.
То, что не убивает нас, делает нас инвалидами.
11.01.2017, 11:21
Ответить

wwwplaton

Если бы это не было бы деревом я бы молча использовал в comments так:
        <ul>
        {%*comments*}
            <li id="comment{*comment_id*}">
                <div>
                    <div>{*comment_text*}</div>
                    <a href="#comment{*comment_id*}">({*reply*})</a>
                </div>         
            </li>
        {%}
        </ul>

Но так как это дерево мне нужно подгружать этот шаблон li.tpl а там уже {*reply*} не работает
11.01.2017, 11:36
Ответить

1234ru

Теперь понятно, что имелось в виду.
Шаблон видит только содержимое массива comment, так что reply надо там продублировать.
То, что не убивает нас, делает нас инвалидами.
11.01.2017, 11:50
Ответить

wwwplaton

я конечно могу щас это сделать при формировании массива. Но я как вспомню сколько других шаблонов я вынес так. что мне аж страшно стало все переписывать :(
11.01.2017, 12:02
Ответить

1234ru

Ну что поделать... Такова область видимости шаблона - только массив, который ему передали.

С другой стороны, странно, что у вас в шаблоне комментария участвует переменная, которая от комментария к комментарию не меняется (т.е. не является его свойством комментария), но при этом все же остается переменной, а не константой (грубо говоря). В чем причина такого подхода?
То, что не убивает нас, делает нас инвалидами.
11.01.2017, 12:46
Ответить

wwwplaton

Наверное и за того что давно пора все переписать с нуля. А то большинство написано было до http://webew.ru/articles/3609.webew#5103 от сюда наверное и такие подходы. Что ж, будем переписывать с учетом полученных знаний и текущих обновлений.
И вот к примеру у меня часто встречается выражения if elseif else как такое можно сделать?
11.01.2017, 13:43
Ответить

1234ru

if elseif else шаблонизатор, к сожалению, не позволяет. Только через вложенные.

Кстати, комментарий #5103 был ровно три года назад, день в день :)
То, что не убивает нас, делает нас инвалидами.
12.01.2017, 05:14
Ответить

wwwplaton

Да, переписал так, получилось что то вроде такого:

Было:
if($user == 0){
    echo "<font color='red'>{$user} / {$maxuser}</font>";
}elseif($user == $maxuser){
    echo "<font color='green'>{$user} / {$maxuser}</font>";
}else{
    echo "{$user} / {$maxuser}";
}

Представили:
if($user == 0){
    echo "<font color='red'>{$user} / {$maxuser}</font>";
}else{
    if($user == $maxuser){
        echo "<font color='green'>{$user} / {$maxuser}</font>";
    }else{
        echo "{$user} / {$maxuser}";
    }
}

Сделали:
{?*user=0*}
    <font color='red'>{*user*} / {*maxuser*}</font>
{?!}
    {?*user=maxuser*}
        <font color='green'>{*user*} / {*maxuser*}</font>
    {?!}
        {*user*} / {*maxuser*}
    {?}    
{?}

Отличный шаблонизатор, как не крути.
12.01.2017, 17:16
Ответить

1234ru

Кстати, можно пользоваться экранированием: если в шаблоне написать {\*reply*}, при обработке это превратится в {*reply*} - без слэша - и замены на переменную не будет.
Экранировать нужно всегда первую звездочку.
То, что не убивает нас, делает нас инвалидами.
11.01.2017, 11:23
Ответить

Arris

Допустимо ли в нынешней версии шаблонизатора использование в шаблоне символов # и @ ?

К примеру, в строках вида:
/@path/@to/@folder
/#path/#to/#folder

Какие еще символы (кроме стандартных открывающих блоков) будут всегда распознаны как управляющие и превратят результат в неудобочитаемую кашу?

P.S. В свое время строка /folder/*/settings сломала работу шаблонизатора нафиг :(
27.06.2017, 11:42
Ответить

1234ru

А зачем вам такие диковинные пути понадобились, если не секрет?
То, что не убивает нас, делает нас инвалидами.
28.06.2017, 07:20
Ответить

Arris

Отличать внутренние "служебные" URLы от неслужебных.

На сайте есть "проекты" и "подпроекты" - соответственно пользователь ходит к ним как:

/project
/project/map

Вместо project и map идут соответственно нормальные алиасы типа /foo/bar , /smart/data итп.

Роутинг делается или через единую точку входа, или через .htaccess , но и в том, и в другом случае нужно писать стену правил типа
RewriteRule ^register$ auth.controller.php?action=register [L,QSA]

Ну с таким правилом все просто, а к примеру редактирование настроек проекта я хочу сделать так:

/simpleproject/~edit

Мда, что-то я всё не то объясняю :( Не с той стороны :(

В общем я хочу с одной стороны сохранить со стороны пользователя простой доступ к проектам/подпроектам, а с другой стороны внутри html/js писать такие же пути, а не банальный actions.controller.php?куча параметров.

Конечно и в имени проекта/подпроекта я запрещаю ряд управляющих символов.
28.06.2017, 13:37
Ответить

Arris

Да я вот сам не могу понять, есть зачем или незачем? :)

В свое время (в 2015 году) просто конструкция {?*aaaaa*} ..... foo/*/bar {*aaaa*?} всё сломала.
28.06.2017, 21:26
Ответить

1234ru

Проверил конкретно этот пример: {?*aaaaa*} ..... foo/*/bar {*aaaa*?}
Он действительно не работает. Но это происходит из-за того, что имя переменной в открывающей конструкции не совпадает с именем в закрывающей: в открывающей пять букв, а в закрывающей - четыре (если это исправить, то пример работает).
Это если не баг, то как минимум неожиданное поведение, но относится оно к устаревшей версии синтаксиса (надеюсь, вы знаете, что современной же версии шаблонизатора можно использовать короткую закрывающую скобку - {?} вместо {*aaaaa*?}), поэтому отлаживать его как-то не хочется :/

Внутрь же if (как и циклов) можно вписывать что угодно, не задумываясь вообще, если это не {*, не {? и не {%. И так, по идее, было всегда.

{?*aaaaa*} ..... foo/*/bar {?} работает как положено.
То, что не убивает нас, делает нас инвалидами.
28.06.2017, 21:30
Ответить

Arris

Ну я в примере то опечатался ;) Конечно там были одинаковые переменные в открывающем и закрывающем теге и это были конечно не aaaaa :)

Я знаю, что в новой версии можно использовать сокращенную запись, но... так к ней и не привык. А вложенность коротких закрывающих скобок оно нормально обрабатывает?

... слушайте, давайте уже на гитхаб перенесем/добавим и напишем нормальный ридми?! :) Красивый, в маркдауне. А то я дла себя написал... на А4 листике, хм, в "инфографике от руки", но это не всегда удобно.

Там и issues нормально выглядят. Нет, ну не нравится гитхаб - можно и гитлаб поднять, у вас наверняка есть где :)
29.06.2017, 00:51
Ответить

1234ru

Цитата:
вложенность коротких закрывающих скобок оно нормально обрабатывает?

Конечно. И циклов это тоже касается.

Именно вложенность явилась причиной, по которой закрывающие скобки были длинными: чтоб поймать конец выражения, нужно было продублировать начало. Другой (более правильный) способ - использовать рекурсивное регулярное выражение. Я очень долго собирался с силами, чтобы его написать (это вообще самая сложная для понимания конструкция в них), вот тогда короткие скобки и появились.
Если разобраться, это, конечно, было неудобно до жути: надо выражение было писать два раза, причем ни там, ни там не ошибиться. Спасало только то, что они обычно короткие.
жесть. Представьте, что в PHP вам нужно условие для if писать два раза. Как-то не очень, правда? :)
Вот я однажды так же решил насчет шаблонизатора. И теперь мы имеем нормальную, короткую, закрывающую скобку.
Попробуйте. Вы быстро привыкнете и вам понравится.

Цитата:
.. слушайте, давайте уже на гитхаб перенесем/добавим и напишем нормальный ридми?! :) Красивый, в маркдауне. А то я дла себя написал... на А4 листике, хм, в "инфографике от руки", но это не всегда удобно.

Именно как ридми и задумывалась эта статья. Должна была читаться легко и давать полное представление о возможностях шаблонизатора. Если вам неудобно ей пользоваться, значит, я сделал что-то не так...

Изначально мне казалось, что Github для шаблонизатора - это как из пушки по воробьям.
Во-первых, это ж всего один файл :)
Во-вторых, сам шаблонизатор настолько простой, что там даже и багов особо не ожидалось (примерно так и было: за шесть лет, как опубликована статья, нашли всего с десяток; на момент публикации это был стабильный работающий код, который более года тестировался на рабочих проектах; багов уже не было, а изменений практически никаких не ожидалось).

Задумывалась максимальная легкость во всем. Прочитал статью, врубился, скачал файлик - работаешь (если не нравится руками - curl (ссылка из статьи) -o (путь, куда скачивать)). Github тут - лишнее звено.

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

Посмотрим... Может, сподоблюсь как-нибудь и выложу. Только описание тогда уж надо на английском делать.
У вас, если что, как с английским? :)
То, что не убивает нас, делает нас инвалидами.
30.06.2017, 05:38
Ответить

Arris

Цитата:
У вас, если что, как с английским? :)

В смысле знаю ли я англ. настолько, чтобы перевести ридми на английский? Нет, но я найду кого оквестовать этим :) Главное собраться. В принципе, язык там простой...

Мечтает об инфографике

Цитата:
Если вам неудобно ей пользоваться, значит, я сделал что-то не так...

Как уже писали выше - за много лет ветка комментариев разрослась настолько, что сама страница грузится как минимум 5 секунд.

В общем пойду-ка я на выходных писать ридми для вашего шаблонизатора так, как его представляю я :)
30.06.2017, 08:56
Ответить

1234ru

Цитата:
пойду-ка я на выходных писать ридми для вашего шаблонизатора так, как его представляю я :)

О, это интересно! Если действительно соберетесь - дайте почитать :)

Инфографика - штука хорошая, но я не очень представляю, как ее применить для описания шаблонизатора. Он для неё слишком простой, мне кажется.

Цитата:
за много лет ветка комментариев разрослась настолько, что сама страница грузится как минимум 5 секунд
Что есть - то есть :| Планируется модернизация, но в какой срок - пока неизвестно.
То, что не убивает нас, делает нас инвалидами.
03.07.2017, 17:23
Ответить

Arris

Кстати, по поводу рекурсивного регулярного выражения я бы с интересом прочитал статью ;-)
30.06.2017, 08:59
Ответить

1234ru

Учту на будущее :)
То, что не убивает нас, делает нас инвалидами.
03.07.2017, 17:25
Ответить

Arris

Кстати,
Цитата:
Итерация по одномерному массиву (вида $DATA['list'] = array(10,20,30,40,50)) делается очень просто. Например, вывести его элементы по одному в строке можно так:

стоит перенести в блок описания массивов :)
01.07.2017, 17:32
Ответить

1234ru

Ну, тут предполагалось, что в главной части статьи итак много информации, можно потерять читателя :) А если кто-то осилил основное до конца, тогда ему можно и про нюансы рассказать.
То, что не убивает нас, делает нас инвалидами.
03.07.2017, 17:28
Ответить
NO USERPIC

astashov

Приветствую.
Опять я пришел сюда со своим отчетом :)

В общем имею следующую проблему:
В шаблоне идет проверка на наличии переменной, и если есть, то выводим данные из массива.
Т.е. буквально вот так
{?*report*}
        {%*report*}
       <tr>
                <td>{*report:worker_id*}</td>
                <td>{*report:department_name*}</td>
                <td>{*report:worker_last_name*} {*report:worker_first_name*} {*report:worker_middle_name*}({*report:worker_role_callsign*})</td>
                <td>{*report:contact_value*}</td>
                <td>{*report:worker_birthdate*}</td>
        </tr>
        {%}
{?}

Ну так вот, если массив больше определенного значения, то php падает в сегфолт, Причем падает он из за того, что проверяется наличие переменной. Т.е. из за {?*report*} перед {%*report*}. Как только убираешь условие перед циклом, отрабатывает нормально(вплоть до 8000 строчек). А если поставить условие, то не больше 407 записей :) Видимо из за размера в виде строки.... Или из за еще чего то.
Причем, совершенно не важно что именно мы проверяем в условии. В данном примере я проверяю report, но пробовал туда вставлять другую переменную, в которой была только цифра 1. Т.е. получается, что условие перед большим циклом приводит php в уныние и зов уйти в заслуженный отдых с кодом завершения 11 :)
07.07.2017, 09:47
Ответить

1234ru

Здравствуйте. Можно шаблон и пример данных? (желательно очищенный)
Хочу своими руками поковырять.
То, что не убивает нас, делает нас инвалидами.
07.07.2017, 13:51
Ответить
NO USERPIC

astashov






<?php
// http://webew.ru/articles/3609.webew
ini_set('pcre.backtrack_limit', 1024*1024);
$WEBSUN_ALLOWED_CALLBACKS = array('date', 'rand', 'implode', 'rawurlencode', 'trim');
include('websun.php');
//
$report = array();
for($i = 1; $i <= 9000; $i++) {
    $report[] = array(
        "worker_id" => 4000013714367,
        "worker_last_name" => "Лучшая фамилия",
        "worker_first_name" => "Неплохое имя",
        "worker_middle_name" => "Классное отчество",
        "worker_role_callsign" => "999999",
        "worker_birthdate" => "2014-12-26 18:00:00+00",
        "department_id" => 4000013714367,
        "department_name" => "Какое то имя тут",
        "contact_value" => "+71234567890"
    );
}
//
echo websun_parse_template(array("report" => $report), "
<center>
<table border='1' cellspacing='0' cellpadding='0'>
        <tr>
                <th>id</th>
                <th>Департмент</th>
                <th>ФИО(позывной)</th>
                <th>Телефон</th>
                <th>Дата рождения</th>
        </tr>
{?*report*}
        {%*report*}
        <tr>
                <td>{*report:worker_id*}</td>
                <td>{*report:department_name*}</td>
                <td>{*report:worker_last_name*} {*report:worker_first_name*} {*report:worker_middle_name*}({*report:worker_role_callsign*})</td>
                <td>{*report:contact_value*}</td>
                <td>{*report:worker_birthdate*}</td>
        </tr>
        {%}
{?}
</table>
</center>
"

);
?>


Вот этот код у меня на серваке приводит к 502 Bad Gateway со стороны nginx(и child ХХХХХ exited on signal 11 (SIGSEGV) со стороны php-fpm ), а если запускать скрипт из консоли, то Segmentation fault

Если {?*report*} заменить на {??*report*}, то выполнится отлично и без ошибок.
07.07.2017, 14:49
Ответить
NO USERPIC

astashov

ах, да

php -v
PHP 5.6.22-0+deb8u1 (cli) (built: Jun 9 2016 07:14:06)
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies
with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2016, by Zend Technologies
07.07.2017, 14:50
Ответить

1234ru

Цитата:
... если массив больше определенного значения, то php падает в сегфолт, Причем падает он из за того, что проверяется наличие переменной. Т.е. из за {?*report*} перед {%*report*}

Да, так и есть. Существует такая архитектурная особенность у этого шаблонизатора (я о ней вспомнил, как только прочитал ваш комментарий с примером; зря я вас заставил потрудиться и выкладывать код, хотя читать его было приятно). Произрастает она из простоты алгоритма: сначала разворачиваем циклы, потом обрабатываем if'ы и затем заменяем переменные/подключаем шаблоны/вызываем функции (третье - все параллельно).

Так вот. Регулярное выражение для if'ов составлено так, что если оно уже начало совпадать (поймало открывающую скобку), то может зажевывать всю строку до конца, даже если в конце не совпадет - чтобы в этом убедиться, ему нужно дойти до конца строки. (В вашем примере с {??*report*} это как раз не так - оно сразу понимает, что совпадения не будет, и это происходит очень быстро.)

Если строка досталась длинная (например, много элементов в массиве, пусть даже шаблон простой), такое поведение кушает много памяти. Иногда получается, что слишком много, и вот выходит так, как у вас. (Кстати, мне понадобилось ровно 2500 записей вместо 407, но это не важно.)
Скажем так, ведет себя регулярное выражение для if'ов неэффективно. Тут есть два исхода. Либо я на него внимательно посмотрю и придумаю, как его сделать более эффективным. Либо посмотрю и пойму, что ничего с ним сделать нельзя и что надо вносить изменения в алгоритм обработки шаблонов.

Но есть тут обходной путь - использовать подшаблон:
{?*report*} {* + *%report* | report.tpl *} {?}

(*%report* означает передачу в подшаблон не самого массива, а каждого из его дочерних элементов.)

Подшаблоны обрабатываются вместе с переменными - на последней стадии, поэтому длина массива им не страшна.

Использование подшаблонов является настолько хорошей практикой, что из-за нее мне лень решать вышеописанную проблему :) Очень редко бывает, что с ними хуже, чем без них. Надеюсь, у вас не такой случай, и использование подшаблона вам подойдет. Если нет - пишите, будем решать проблему.

P.S. Кстати, в вашем случае проверка на {?*report*} и вовсе лишняя. У вас внутри if нет ничего, кроме цикла. Если массив окажется пуст, то цикл даст пустую строку, будто его там и нет.
То, что не убивает нас, делает нас инвалидами.
07.07.2017, 16:23
Ответить
NO USERPIC

astashov

Это в примере ничего дальше ничего нет. В оригинальном шаблоне есть блок else, который сообщает что сотрудников нет и так далее.
Попробую в понедельник переписать на подшаблоны. Потом сообщу.

Но в описание по массивам думаю можно описать этот частный случай и вариант ее решения. Я честно говоря два дня потратил на то что бы локализовать проблему :) И пыху, и фпм-ку :) и что только не делал :)
07.07.2017, 16:41
Ответить

1234ru

Да, проблема эта уже второй или третий раз встречается (хоть за шесть лет и немного, но сколько еще тех, кто поленился написать?). Добавил в статью пояснение.
То, что не убивает нас, делает нас инвалидами.
07.07.2017, 17:38
Ответить

wwwplaton

а реально такое на JS накатать? Что б он кушал JOSN с аякс запроса?
08.07.2017, 18:01
Ответить

1234ru

Вы имеете в виду переписать шаблонизатор, чтоб он мог работать на javascript?
То, что не убивает нас, делает нас инвалидами.
10.07.2017, 10:18
Ответить

wwwplaton

да именно это меня и мучает :))
10.07.2017, 12:06
Ответить

1234ru

Существует ли такая техническая возможность - это я вам сразу не скажу (может, и нет, потому что в javascript регулярные выражения послабее: например, не поддерживаются заглядывания назад; не знаю, поддерживается ли рекурсивные шаблоны, если нет - то точно не выйдет).
Но скажу вот что:
1) Говорят, есть много средств, которые могут в браузере решать такую задачу - подставлять содержимое в шаблон. Правда, я навскидку ни одного не назову сейас :) (сам не пользуюсь). Но они есть.
2) Если честно, я бы на вашем месте тянул с сервера уже готовый HTML. Да, это не так экономно, но зато у вас очень упрощается логика на клиенте (сам так делаю; объемы обычно небольшие, так что JSON 1 Кб или HTML 2 Кб погоды не делают).

Если вам все-таки хочется это делать на клиенте - расскажите хоть, что у вас за случай.
То, что не убивает нас, делает нас инвалидами.
10.07.2017, 16:08
Ответить

wwwplaton

Ну основное это таблицы, много таблиц и как бы пофигу. Но тут я накатал комментарии. Вывод на страницу обычный, но добавление идет аяксов и соответственно на место будущего коммента становится форма, а потом после добавления она заменяется на комментарий добавленный. Так вот что б учесть все 8 IF и прочее в самом комментарии я и столкнулся с гемором, в зависимости от настроек меняется не только вид но и доступ (гость, пользователь) и когда я начал это делать на JS я понял что это такое гэ :((
11.07.2017, 14:49
Ответить

1234ru

Ну вы же можете и форму, и добавленный комментарий получать по AJAX с сервера в виде готового HTML. Все, что надо сделать на клиенте - это сказать, куда вставлять (с помощью jQuery, например, это проще простого).
То, что не убивает нас, делает нас инвалидами.
12.07.2017, 13:42
Ответить

wwwplaton

возможно я сильно заморочился:)))
12.07.2017, 18:51
Ответить
NO USERPIC

astashov

Работает. Спасибо.
10.07.2017, 08:41
Ответить
NO USERPIC

enotniy

Залейте на github пожалуйста, уже замучился каждый раз этот эту статью искать. А коменнтарии уже разрослись, что найти тяжело конкретный вопрос
31.08.2017, 07:46
Ответить

1234ru

Уговорили :)
https://github.com/1234ru/websun
То, что не убивает нас, делает нас инвалидами.
31.08.2017, 12:54
Ответить
NO USERPIC

astashov

Вот еще полноценный readme файл бы, и тогда норм было бы
12.09.2017, 09:10
Ответить

1234ru

В качестве readme должна выступать эта статья. Я не знаю, как еще более сжато, но при этом понятно, изложить возможности шаблонизатора :|
Может, кто-нибудь покажет :)
То, что не убивает нас, делает нас инвалидами.
12.09.2017, 09:26
Ответить

Virtus-pro

Здравствуйте

А будет ли работать шаблонизатор на PHP 7 ?
Например в PHP отключили функцию preg_replace и теперь только preg_replace_callback
У вас в шаблонизаторе я вижу, что вы используете устаревшую функцию, получается не будет работать да ?
Есть шанс, что вы переделаете?

Можете еще вот подсказать, у меня на одном сайте свой шаблонизатор и перевожу его на PHP 7, так вот не могу один кусок тоже побороть
$in["#\[index:(.+?)\](.*?)\[/index\]#ies"] = "indexShow('\\1', '\\2')";
$in["#\[modules:(.+?):(.+?)](.*?)\[/modules]#ies"] = "modulesShow('\\1', '\\2', '\\3')";

$in["#\[guest](.*?)\[/guest]#ies"] =  "checkGuest('\\1')";
$in["#\[user](.*?)\[/user]#ies"] =  "checkUser('\\1')";
$in["#\[title:(.*?)]#ies"] =  "\$this->preTitle('\\1');";
$in["#\[open](.*?)\[/open]#ies"] =  "\$this->preOpen('\\1');";
$in["#\[userinfo:(.*?)]#ies"] =  "\$this->ustinf('\\1')";

$text = preg_replace(array_keys($in), array_values($in), $str);


Подскажите как переделать из preg_replace в preg_replace_callback?
07.09.2017, 18:01
Ответить

1234ru

У меня на одном из серверов PHP 7.1.6 (самый свежий на данный момент), там все прекрасно работает.
preg_replace никто убирать не собирается :) Вот посмотрите: http://php.net/preg_replace, никаких упоминаний о чем-то подобном (да и было бы странно; хорошая мощная библиотека).
Вы, вероятно, путаете preg_replace с ereg_replace, вот её действительно уберут :)
То, что не убивает нас, делает нас инвалидами.
08.09.2017, 10:31
Ответить

Virtus-pro

Да, я проверил уже, все работает)
так же узнал, что вот такая конструкция именно не будет работать в PHP 7
$text = preg_replace(array_keys($in), array_values($in), $str);

Если не писать в эту функциями массивом, то сообщение об ошибке не выкидывает
08.09.2017, 13:20
Ответить

1234ru

У вас, видимо, ошибка в чем-то другом. preg_replace() как принимала массивы, так и принимает :) (и в документации по-прежнему про это написано).

У меня вот такой пример работает:

$str = 'abcd';

$in = [
    '/a/' => 1,
    '/b/' => 2,
];

$text = preg_replace(array_keys($in), array_values($in), $str);

echo $text; // 12cd
То, что не убивает нас, делает нас инвалидами.
08.09.2017, 14:08
Ответить

Virtus-pro

Работает, странно.
Просто если вы вставите код который у меня выше, то получается такая ошибка
Warning: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead
08.09.2017, 14:13
Ответить

1234ru

У вас во всех выражениях есть этот модификатор: ...[/index]#ies и т.п.
Непонятно, зачем он вам нужен. Просто уберите его :)
То, что не убивает нас, делает нас инвалидами.
08.09.2017, 14:57
Ответить
NO USERPIC

ashechuk

Вопрос решился сам собой)
не любишь mikrotik, ты просто не умеешь его готовить.
04.12.2017, 03:06
Ответить
Добавить комментарий
Отображение комментариев: Древовидное | Плоское
© 2008—2017 webew.ru, связаться: x собака webew.ru
Сайт использует Flede и соответствует стандартам WAI-WCAG 1.0 на уровне A.
Rambler's Top100

Реклама: