MODx/Подключаемые плагины/PHx

Введение

править

PHx (Placeholders Xtended) добавляет новые возможности для отображения плейсхолдеров, тегов MODx (включая TV параметры) и теги настроек сайта. Рекурсивный парсер позволяет использовать вложенные теги. Возможно создавать свои модификаторы, путем создания сниппетов.

Загрузка

править

Скачать последнюю версию PHx из репозитория MODx можно по этой ссылке. Текущая версия 2.2.0

Установка

править

Новая установка

править
  1. Скачайте и распакуйте архив.
  2. Создайте директорию "phx" в папке /assets/plugins.
  3. Закачайте через FTP или просто скопируйте содержимое архива в /assets/plugins/phx
  4. Создайте новый плагин "PHx" в Панели управления MODx (Элементы-Управление элементами-Плагины) и скопируйте в поле "Код плагина (php)" содержимое файла phx.plugin.txt
  5. Отметьте событие "OnParseDocument" на вкладке "Системные события"

Обновление

править
  1. Скачайте и распакуйте архив.
  2. Переименуйте директорию /assets/plugins/phx в /assets/plugins/phx-old
  3. Создайте директорию "phx" в папке /assets/plugins.
  4. Закачайте через FTP или просто скопируйте содержимое архива в /assets/plugins/phx
  5. Создайте новый плагин "PHx" в Панели управления MODx (Элементы-Управление элементами-Плагины) и скопируйте в него содержимое файла phx.plugin.txt
  6. Отметьте событие "OnParseDocument" на вкладке "Системные события"

Настройка

править

На вкладке конфигурация, во время редактирования плагина скопируйте в поле "Конфигурация плагина":

[pseudocode,N]&phxdebug=Лог событий;int;0 &phxmaxpass=Макс. число проходов;int;50

Для опытных пользователей

править

Вы можете изменить настройки по умолчанию для плагина PHx:

  • Лог событий
0 = Отключен
1 = Включено логирование событий PHx
Если включено PHx создает подробный лог на каждое событие, записанное в протоколе событий ( Отчеты->Просмотр событий)
  • Макс. число проходов
Определяет максимально обрабатываемую глубину вложенных тегов. Рекомендуется оставить значение 50.

Описание

править

PHx (Placeholders Xtended) расширяет возможности использования плейсхолдеров, тегов содержимого (включая TV параметры) и тегов настройки сайта. Благодаря этому вы можете с легкостью определять формат вывода конечного результата. PHx встраивается в парсер MODx, расширяя его функционал модификаторами, условиями и в качестве бонуса делает его по-настоящему рекурсивным. PHx также избавляет от необходимости в маленьких сниппетах, которые используются только для форматирования выводимых значений.

Великолепно для шаблонов!

Преобразовать значение так же просто, как добавить :modifier.


Поддерживаемые теги

править

PHx поддерживает следующие теги MODx:

  • [+placeholder+]
  • [*теги содержимого*] ([*content*], [*pagetitle*], например)
  • [*TV параметры*]
  • [(теги настройки)] (например, [(base_url)], [(site_name)] и другие)

Сниппеты, поддерживающие PHx

править
  • Ditto
  • Jot
  • MaxiGallery

Вы можете использовать PHx синтаксис в чанках, используемых сниппетами не из этого списка, но для этого требуется другой метод (см. раздел Tips & Tricks)

Использование

править

Обычный плейсхолдер вида [+placeholder+] легко превращается в плейсхолдер PHx: [+placeholder:esc+]. Тоже самое вы можете сделать с тегом содержимого:

[*createdby*]

Добавляем модификатор:

[*createdby:date=`%a %B %d, %Y at %H:%M`*]

Также можно использовать несколько модификаторов сразу. Они будут обработаны слева направо:

somevar:esc:nl2br:strip

Расширенное применение

править

Наличие специального плейсхолдера "phx" позволяет использовать синтаксис PHx без наличия реальной переменной.

[+phx:if=`[+this+]`:is=`[+that+]`:then=`do this`:else=`do that`+]

С некоторыми модифиакторами этот плейсхолдер приобретает определенное значение. В случае с модификатором "userinfo" он возвращает соответствующее значение из информации о текущем пользователе:

[+phx:userinfo=`username`+]

Известные проблемы

править
Синтаксис
править

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

[+
[*
[(
+]
*]
)]
]]

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

array[counter++]

... которая спровоцирует странное поведени из-за +]. Также закрывающий тег CDATA:

/* ]]> */

... может создать проблемы.

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

Модификаторы

править

Строки

править

Возвращает строку, приведенную к нижнему регистру.

Example:

[pseudocode,N][+string:lcase+]

  • Input: [pseudocode,N]Это СтроКа
  • Returns: [pseudocode,N]это строка

Приведет все символы строки к верхнему регистру.

Example:

[pseudocode,N][+string:ucase+]

  • Input: [pseudocode,N]This is a string
  • Returns: [pseudocode,N]THIS IS A STRING

Первая буква в строке станет заглавной.

Example:

[pseudocode,N][+string:ucfirst+]

  • Input: [pseudocode,N]иванов
  • Returns: [pseudocode,N]Иванов

Обрежет строку.

Example:

[[+description:ellipsis=`150`]]

length | len

править

Возвратит длину строки.

Example:

[pseudocode,N][+string:len+]

  • Input: [pseudocode,N]this is a string
  • Returns: [pseudocode,N]16

Вырежет все HTML теги из строки.

Example:

[pseudocode,N][+string:notags+]

  • Input:[pseudocode,N]this is a string
  • Returns: [pseudocode,N]this is a string

Удаляет html теги и разрывы строк

Конвертирует исходную переменную в html сущности. Аналог htmlentities() в PHP.

Конвертирует символы перевода строки в теги.

Example:

[pseudocode,N][+string:nl2br+]

  • Input: [pseudocode]

this is a string

  • Returns: [pseudocode,N]this is
    a string

Удалит символы новой строки(\n), табуляторы(\t), идущие подряд пробелы.

Пример:

[pseudocode,N][+string:strip+]

  • На входе:
this is 
a 
string
  • Вернет: [pseudocode,N]this is a string

Другие модификаторы

править
  • reverse
    Перевернет задом наоборот буквы.
  • wordwrap(=`length`)
    length - characters
    Breaks words in the current value longer than the given length of characters by putting a space in between.
    Default: 70 characters.
  • limit(=`length`)
    Возвратит первые X символов от текущего значения.
    По умолчанию: 100 символов.

Специальные

править

date(=`dateformat`)

править
  • dateformat: В соответствии с форматом PHP-функции strftime
  • Преобразует метку времени unix timestamps в соответствии с заданным форматом.

Пример:

[*createdon:date=`%d.%m.%Y`*]

Для того, чтобы дата выводилась в соответствии с текущим языком сайта, необходимо установить локаль в начале кода плагина PHx. Пример ниже установит локаль для Германии:

[php]setlocale(LC_ALL, 'de_DE@euro', 'de_DE', 'de', 'ge');

  • Создает MD5-хэш текущего значения.

userinfo=`field`

править
  • field: Similar to the fields used in the database. Like: username, useremail

Formats a userid value (webuser have negative ids) to a field specified.

math=`calculation`

править
  • Use simple calculations like - * + /.
  • The "?" character is replaced by the current value of the extension but you can also use nested tags.
  • Example calculation: ?+1+(2+3)+4/5*6

ifempty=`other value`

править
  • Use "other value" when the output of the placeholder/templatevar is empty.

select=`options`

править

Translates the value of placeholder/templatevar to a specified output.

  • options like: value1=output1&value2=output2

Example:

  • Input: 1

[pseudocode,N][+placeholder:select=`0=OFF&1=ON&2=UNKNOWN`+]

  • Returns ON

Условные выражения

править
  • alias: eq

равно (==)

  • alias: isnot, isnt

не равно (!=)

  • alias: isgt

больше или равно (>=)

  • alias: islt

меньше или равно (<=)

больше (>)

меньше (<)

mo=`Webgroups`

править
  • синонимы(алиасы): isinrole, ir, memberof

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

Пример:

[+phx:mo=`Администраторы`:then=`Я админ`:else=`Я простой смертный`+]

if =`value`

править

Принимает в качестве параметра переменную для сравнения. Также может быть использовано в сочетании с :or или :and.

Пример:

[+phx:if=`[+price+]`:gt=`0`:then=`Цена: [+price+]`+]

Логическое ИЛИ (проверяется, верно ли первое или второе условие).

[+phx:if=`[*id*]`:is=`2`:or:is=`3`:then=`{ {Chunk} }`:else=`{ {OtherChunk} }`+]

В данном примере если текущий ID равен 2 или 3, то выводится чанк { {Chunk} }, иначе выводится чанк { {OtherChunk} }.

Логическое И (проверяется, верны ли оба условия).

[+phx:if=`[!UltimateParent!]`:is=`1`:and:isnot=`[*id*]`:then=`{ {ChildChunk} }`:else=`{ {ParentChunk} }`+]

В данном примере если UltimateParent равен 1 и при этом не равен текущему ID, то выводится чанк { {ChildChunk} }, иначе выводится чанк { {ParentChunk} }.

then =`template`

править

Значение template отображается, когда все условия верны. Здесь можно указать вызов { {чанка} }, [ [сниппета] ] или же чистый HTML.

else =`template`

править

Значение template отображается, когда условия не верны. Здесь можно указать вызов { {чанка} }, [ [сниппета] ] или же чистый HTML.

Используется подобно then, но в качестве шаблона для вывода используется исходное значение. Выполняется, если условия верны.

[pseudocode,N][+myplaceholder:len:gt=`3`:show+]

В данном примере значение плейсхолдера будет выведено, если его длина составляет более 3 символов.

Дополнительные примеры

править
Пример 1
править

Допустим. что myplaceholder имеет значение myvalue.

[+myplaceholder:is=`myvalue`:then=`Правильно`:else=`Неправильно`+]

Вызов вернет: Правильно


  • [+myplaceholder:isnot=`myvalue`:then=`Правильно`:else=`Неправильно`+]
  • [+myplaceholder:is=`othervalue`:then=`Правильно`:else=`Неправильно`+]

Оба примера вернут: Неправильно

Пример 2
править

Исходные данные

  • myplaceholder имеет значение 2
  • someplaceholder имеет значение 3
  • otherplaceholder имеет значение 1

[html] [+myplaceholder:is=`2`:then=`{ {ChunkGood} }`:else=`{ {ChunkBad} }`+]

Результатом выполнения примера станет вызов чанка с именем ChunkGood.

Прочие примеры
править

  • [+myplaceholder:gt=`1`:then=`Yes`:else=`No`+]
  • [+myplaceholder:lt=`3`:and:gt=`1`:then=`Yes`:else=`No`+]
  • [+myplaceholder:lt=`[+someplaceholder+]`:then=`Yes`:else=`No`+]
  • [+myplaceholder:islt=`2`:then=`Yes`:else=`No`+]
  • [+myplaceholder:isnot=`2`:or:lt=`3`:then=`Yes`:else=`No`+]

Все примеры вернут Yes.


  • [+myplaceholder:isnot=`2`:then=`Yes`:else=`No`+]
  • [+myplaceholder:gt=`[+someplaceholder+]`:then=`Yes`:else=`No`+]
  • [+myplaceholder:lt=`2`:then=`Yes`:else=`No`+]
  • [+myplaceholder:gt=`2`:then=`Yes`:else=`No`+]
  • [+myplaceholder:lt=`1`:then=`Yes`:else=`No`+]

Все примеры вернут No.

Пользовательские модификаторы

править

Модификатор представляет собой простой сниппет, который обрабатывает заданное значение. Существует возможность создавать свои собственные модификаторы/мини-сниппеты, добавив новый сниппет в менеджере ресурсов MODx или же создав файл в папке модификаторов плагина PHx.

Поскольку код модификатора несложен, то ему не нужны никакие параметры, за исключением тех, которые он получает от парсера.

Существуют две основные переменные:

  1. $output - содержит текущее значение переменной, которую необходимо модифицировать.
  2. $options - необязательный параметр, значение которого передается в модификатор.

Приведем пару примеров использования модификаторов. Допустим, что плейсхолдер myplaceholder имеет значение "test":

[+myplaceholder:mymodifier+]

  • Переменная $output содержит значение "test".
  • Переменная $options не содержит ничего, т.к. модификатору не был передан параметр.

[+myplaceholder:mymodifier=`my options`+]

  • Переменная $output все еще содержит значение "test".
  • Переменная $options теперь содержит значение "my options".

Прочие переменные (для продвинутых пользователей)

  • $input - содержит исходное немодифицированное значение.
  • $condition - массив, содержащий элементы, образующие условное выражение (0, 1, || и &&).

Создание собственного модификатора

править

Пример 1: I love MODx

править

Используя полученные знания, создадим новый пользовательский модификатор. Это будет модификатор без параметра, который просто добавит текст " because I love MODx" к переменной. Для этого необходимо проделать следующие шаги:

  1. В Менеджере ресурсов надо зайти в Ресурсы(Элементы) -> Управление ресурсами (элементами) -> Сниппеты
  2. Нажать "Новый сниппет"
  3. В качестве имени сниппета задать "phx:love"
    Для того, чтобы сниппет воспринимался как модификатор для PHx, его название должно иметь префикс "phx:" без пробелов между ним и собственно именем сниппета. Тогда можно будет его использовать как модификатор, добавив :love к любому плейсхолдеру, например: [+myplaceholder:love+].
  4. Теперь добавим код модификатора в поле для кода. Допустим, это будет код следующего вида:
     <?php $newvalue = $output. " because I love MODx"; return $newvalue; ?>
  5. Сохраним изменения и наш новый модификатор (:love) готов к использованию!

Пример 2: I love MODx even more

править

Создадим модификатор, подобный модификатору :love из предыдущего примера, но дополнительно дадим ему возможность добавлять к исходной строке значение переданного параметра, если оно было указано.

  1. В Менеджере ресурсов надо зайти в Ресурсы(Элементы) -> Управление ресурсами (элементами) -> Сниппеты
  2. Нажать "Новый сниппет"
  3. В качестве имени сниппета задать "phx:love2"
    Для того, чтобы сниппет воспринимался как модификатор для PHx, его название должно иметь префикс "phx:" без пробелов между ним и собственно именем сниппета. Тогда можно будет его использовать как модификатор, добавив :love к любому плейсхолдеру, например: [+myplaceholder:love2+].
  4. Теперь добавим код модификатора в поле для кода. Допустим, это будет код следующего вида:
    <?php return $output . (strlen($options)>0 ? $options : ' because I do love MODx'); ?>
  5. Сохраним изменения и наш новый модификатор (:love2) готов к использованию!

Условные модификаторы

править

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

[php] <?php $condition[] = intval(file_exists($output)); ?>

В данном примере происходит проверка на наличие файла.

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

  • [+phx:if=`assets/images/path/to/your/file.jpg`:fileexists:then=`Файл существует!`:else=`А был ли файл?`+]
  • [+myimage:fileexists:then=`Файл существует!`:else=`А был ли файл?`+]
  • <img src="[+myimage:fileexists:then=`[+myimage:phpthumb=`w=200`+]`:else=`[+phx:input=`path/to/blank/image.jpg`:phpthumb=`w=200`+]`+]" />

Дополнительные модификаторы

править

Установка

править
  1. Войдите в административную панель MODx
  2. Пройдите во вкладку Элементы > Управление элементами > Сниппеты
  3. Создайте новый сниппет с префиксом "phx:"
  4. Скопируйте и вставьте код сниппета
  5. Сохраните сниппет

или

  1. Создайте новый файл с названием "имя_сниппета.phx.php" в assets/plugins/phx/modifiers/ (Например: assets/plugins/phx/modifiers/phpthumb.phx.php)
  2. Скопируйте код сниппета в этот файл
  3. Выставите права на файл 0555 (если хотите достичь максимальной безопасности)

Коды модификаторов

править
  • описание : возвращает 7bit код строки
  • применение: [+string:7bit+]
<?php
   
      $text = mb_convert_encoding($output,'HTML-ENTITIES',mb_detect_encoding($output));
  
      $text = preg_replace(array('/ß/','/&(..)lig;/','/&([aouAOU])uml;/','/&(.)[^;]*;/'),array('ss',"$1","$1".'e',"$1"),$text);
   
      return $text;
   
      ?>

Tips and Tricks

править

Using PHx in non-phx snippet templates

править

Most snippets render their templates "locally" before they are passed to MODx. Unless the snippet's description states it's using PHx to render the templates it's not possible to use the modifiers directly, however you still CAN use PHx by using a special modifier called phx:input.

This example will not work with a non-PHx snippet:

[+myplaceholder:modifier1:modifier2+]

Try this method instead:

[+phx:input=`[+myplaceholder+]`:modifier1:modifier2+]

Or:

[*phx:input=`[+myplaceholder+]`:modifier1:modifier2*]

This example will work with a non-PHx snippet. Some restrictions may apply depending on the snippet logic.

Technical Documentation

править

Эта часть не интересна большинству пользователей. Но здесь раскрываются секреты работы PHx.

PHx запускается при наступлении события OnParseDocument. OnParseDocument вызывается до того, как стандартные теги MODx будут обработы, поэтому PHx обрабатывает чистый (сырой) шаблон.

Этапы работы

  1. Начинаем если не превышено максимальное количество проходов.
  2. Сохраняем хэш текущего содержимого, чтобы обнаружить изменения после обработки.
  3. С помощью специальных фильтров избавляемся от ненужных символов (которые не являются частью тегов MODx).
  4. Содержимое документа попадает в основную функцию:
    1. A hash is made of the current content of the document to check for changes in the process later on.
    2. Chunks are merged using mergeChunkContent (MODx API).
    3. Snippets are detected using an advanced regular expression that takes nested tags into account:
      1. Snippet calls which contain no nested tags are matched.
      2. Each matching call is checked for (non-)cached output, prepared and passed to evalSnippets (MODx API).
    4. Snippet output is merged with the document.
    5. The rest of the MODx tags are detected using an advanced regular expression that takes nested tags into account:
      1. Document/Template Variable output is gathered from mergeDocumentContent (MODx API).
      2. Setting Variables output is gathered from mergeSettingsContent (MODx API).
      3. Placeholder output is gathered in the following order PHx, MODx.
      4. If the requested placeholder is not set it is skipped for the current pass (replaced with original).
    6. For each detected tag, the ones which also contains modifiers are passed to the filter that will modify the value as given.
    7. The final output for all tags is then merged into the document.
    8. A hash is made of the content of the merged document and compared to the initial hash to check if there were changes.
    9. If we did not reach maximum passes AND if the document content has changed we repeat this entire level (pass+1).
  5. The document's rogue bracket characters are restored to their non-escaped versions.
  6. The tags that are still present (and thus unresolved for the entire document) are removed from the output.
  7. A hash is made of the new document content and compared to the initial hash to check if there were changes.
  8. If the document content has changed let it repeat this entire level.
  9. Log the parser steps into the Event Log if required.
  10. Return the new documentOutput to MODx.

After the entire PHx logic is through, it's 99% certain that MODx does not have any tags left to parse. You could say that PHx replaces the core function of MODx that handles the merging (with added flexibility by allowing nesting). However, the different types of elements are still processed by the responsible MODx functions.