MODX
PHP
September 2015 14

QuadBraces — по мотивам парсера MODx

Доброго здравия хабражителям!

Когда я заглянул в исходники MODx Evolution, меня едва ли не хватил удар. Рефакторить, рефакторить и рефакторить, как, наверное, сказал бы Ильич. По сему меня хватило едва ли на пару недель рефакторинга, после чего я забросил это дело, ибо времени откровенно не было. Но разговор пойдёт не об этом.

Система шаблонизации MODx на мой взгляд — одна из самых лучших. Особенно хорошо постарались разработчики в MODx Revolution. Всё логично, расширяемо, гибко и прям-таки пасторально. Можно сказать, синтаксис шаблонизации MODx — это почти что отдельный язык разметки. Именно такое вот восхищение стало причиной, по которой я стал использовать эту методику в других проектах. И для того, чтобы не заколачивать микроскопом гвозди, то есть не ставить для лендингов MODx, но иметь возможность использовать эту шаблонизацию, я написал отдельный класс шаблонизатора. И даже дал название — QuadBraces.

Однако, первое, о чём хочу предупредить — это то, что привычные MODx-ерам чанки, шаблоны, сниппеты и расширения в парсере хранятся не в БД, а в файлах. Путь к файлу с данными шаблона определяется путём определения константы QBPARSER_TPL_PATH.

Возможности


  • Рекурсивная обработка текстовых данных;
  • Используемые типы элементов: чанки, константы, установки, плейсхолдеры, отладка, сниппеты, языковые конструкции, автоитераторы;
  • Возможность определения т.н. темплейт-паков (в папке шаблонов парсера), что позволяет разрабатывать, устанавливать и использовать готовые пакеты шаблонов (как в Неназываемом-Мною-Обычно-Движке);
  • Возможность структурирования шаблонного контента. Точка в алиасе чанка / шаблона / сниппета означает фактически разделитель директории;
  • Ошибки генерируют исключения, что позволяет легче отлаживать код;
  • Установка массива плейсхолдеров и «настроек» подразумевает дополнение существующих данных;
  • Готовые алгоритмы аксессоров;
  • В отличие от MODx глубина вложенности сниппетов ограничена только максимальным уровнем обработки парсера.


В сущности данный класс представляет собой рекурсивный обработчик текста на регулярках. Данные для плейсхолдеров и «настроек» определяются конечным разработчиком. Точно также и со сниппетами — это всё уже на совести того, кто будет использовать этот класс. В смысле сами пишите =)

Исходник класса доступен на GitHub здеся — github.com/XanderBass/quadbraces

Пример использования парсера:

<?php
  require 'qbparser.php';
  
  $parser = new QuadBracesParser();
  $parser->templatePack = 'default'; // Устанавливаем шаблон-пак
  $parser->template = 'index'; // Устанавливаем сам шаблон
  $parser->data = array(
    'foo' => 'bar',
    'pagetitle' => 'Тестовая страница',
    'content' => 'Hello world!'
  );
  $parser->settings = array(
    'my_setting' => 'Моя настройка аднака'
  );
  echo $parser;
?>


Обращаю внимание, что парсер поддерживает языковые конструкции. Словари должны содержаться в языковой папке (по умолчанию QBPARSER_TPL_PATH.'lang'.DIRECTORY_SEPARATOR), где каждая подпапка соответствует по своему имени языковой сигнатуре (например, en или ru). Каждый файл словаря должен иметь расширение lng и содержать набор строк, разделённых символом "|". Первый элемент такой строки является ключом, второй — элементом caption, третий — элементом hint.

При поиске чанков, шаблонов и сниппетов (и расширений) производится поиск т.н. локализованных элементов. Эта возможность позволяет создавать отдельные реализации чанков для определённых языков.

Кстати, к вопросу о переменных. Фактически добавить переменную равно добавлению плейсхолдера.
<?php
  $parser->data = array(
    'items' => array(
      array('id' => 1,'title' => 'Элемент 1'),
      array('id' => 3,'title' => 'Элемент 3'),
      array('id' => 2,'title' => 'Элемент 2')
    )
  );
?>

Этот код не приведёт к перезаписи всего массива data парсера. Этот код перезапишет лишь элемент «items» этого массива, если тот существует (если нет, создаст).

Поддерживаемые раширения


is, eq — равенство (сравниваемое значение, then, else)
isnot, neq — неравенство (сравниваемое значение, then, else)
lt — меньше, чем (сравниваемое значение, then, else)
lte — меньше, чем, или равно (сравниваемое значение, then, else)
gt — больше, чем (сравниваемое значение, then, else)
gte — больше, чем или равно (сравниваемое значение, then, else)
even — признак чётности (сравниваемое значение, then, else)
odd — признак нечётности (сравниваемое значение, then, else)
for — целочисленный итератор (количество итераций, start, splitter)
foreach — индексный итератор (список индексов через запятую, splitter)

— Для расширения for доступен внутренний плейсхолдер [+iterator+], содержащий
номер текущей итерации
— Для расширения foreach доступны внутренние плейсхолдеры:
[+iterator.index+] — номер позиции текущей итерации
[+iterator+] — текущий индекс

Примеры возможностей



{{path.to.my-chunk}}
выведет обработанное содержимое чанка, находящегося в файле /path/to/my-chunk.html в папке парсера. Как я уже говорил, возможность позволяет структурировать данные шаблонов, не сваливая всё в одну кучу.

{{my-chunk &foo=`bar`}}
выведет обработанное содержимое чанка my-chunk, заменив внутри него плейсхолдер [+foo+] на строку «bar». Эта фича позволяет обходиться без громоздких сниппетов-итераторов. Надо вывести в лендинге десяток проектов? Нет ничего проще! Создаём чанк вывода проекта, а на странице тупо несколько раз его вызываем, подставляя нужные локальные параметры — PROFIT!

[*cool-data &foo=`bar`*]
то же, что и выше, только с плейсхолдером cool-data.

[*cool-data:empty=`bar`*]
если плейсхолдер cool-data будет пустым, выведется строка «bar»

{*MY_CONSTANT*}
выведет содержимое константы MY_CONSTANT, если таковая определена. Работает с любыми константами. Аккуратнее с «волшебными» константами. Иногда случаются любопытные вещи.

[!my.cool.snippet:empty=`пустонафик` &argument=`foobar`!]
Выполнит сниппет my/cool/snippet.php из папки шаблона, передав в качестве аргументов массив, содержащий элемент с индексом argument и значением «foobar». Если результат работы сниппет будет пустым, выведет строку «пустонафик».

{{my_chunk:for=`6`:splitter=`< br / >`}}
выведет чанк my_chunk 6 раз, разделив при этом вывод при помощи тега < br / > (убрать пробелы в теге)

[%error-message.hint%]
выведет HINT языкового элемента error-string, если язык загружен

В общем бесконечно можно фантазировать о применении этого парсера. Базовые примеры есть в README на GitHub. По сему экспериментируйте. В комментариях задавайте вопросы, а также пишите об ошибках, если таковые будут. Я проверял — всё работает.

UPD 1:
— Теперь доступно на GitHub здеся — github.com/XanderBass/quadbraces
— По многочисленным заявкам (здесь была ирония) добавлены итераторы
— Код отформатирован немного лучше
— Добавлены языковые конструкции и поиск локализованных версий файловых элементов

UPD 2:
— Добавлены автоитераторы элементов массива data, являющихся массивами
А Вы делаете лендинги на MODx
29.5% Я всё делаю на MODx 44
12.7% Иногда делаю 19
2.6% Только по очень жуткой необходимости 4
55% Да нафиг надо! 82
Voted 149 users. Passed 52 users.
+5
7.6k 39
Comments 49
Top of the day