Разделы

Прямой эфир

Весь эфир | RSS

pHx против Jot, AjaxSearch и Ditto. Или как не дать на съедение pHx плэйсхолдеры.

Все задавались проблемой пропадания содержимого плейсхолдеров [! Jot !] [+jot.html.form+] и [+jot.html.comments+] на кэшируемой странице. На буржуйских форумах советовали вызывать этот сниппет вместо плэйсхолдера с параметром «action». Но зачем нам лишняя гора запросов!

Итак в http://modxcms.com/forums/index.php?topic=45121.0 сказали, что проблема в pHx.
Скурпулезно просмотрев код и логи парсера pHx, наткнулся на кусок кода:

preg_match_all('~\[(\+|\*|\()([^:\+\[\]]+)([^\[\]]*?)(\1|\))\]~s', $template, $matches);
                        if ($matches[0]) {
                                $template = str_replace($matches[0], '', $template);
                                $this->Log("Cleaning unsolved tags: \n" . implode("\n",$matches[2]) );
                        }


Вывев этот самый массив $matches[0], я увидел там мои плэйсхолдеры, которые парсер следующей строчкой вырезал.

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

Короче говоря, теперь вопрос состоял в том, чтобы не давать парсеру удалять пустые плейсхолдеры, пока все сниппеты не будут выполнены.

Открываем phx.parser.class.inc.php

После

var $placeholders = array();

добавляем две переменные:

var $snippetsQuantity=0; 
var $snippetsParsed=0;

Они будут отображать количество сниппетов на странице и кол-во обработанных сниппетов соответственно.

Затем после строчки

$template = $modx->documentOutput;

вставляем код подсчета всех сниппетов.

preg_match_all('~\[(\[|\!)(.*?)(\]|\!)\]~s', $template, $matches);              
$this->snippetsQuantity=count($matches[0]);

Следовательно меняем код:

preg_match_all('~\[(\+|\*|\()([^:\+\[\]]+)([^\[\]]*?)(\1|\))\]~s', $template, $matches);
                        if ($matches[0]) {
                                $template = str_replace($matches[0], '', $template);
                                $this->Log("Cleaning unsolved tags: \n" . implode("\n",$matches[2]) );
                        }

на

if ($this->snippetsParsed > $this->snippetsQuantity || ($this->snippetsQuantity==0) )
                {
                        
                        preg_match_all('~\[(\+|\*|\()([^:\+\[\]]+)([^\[\]]*?|)(\1|\))\]~s', $template, $matches);                               
                        if ($matches[0]) {
                                $template = str_replace($matches[0], '', $template);
                                $this->Log("Cleaning unsolved tags: \n" . implode("\n",$matches[2]) );
                        }
                }

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

После строк

$replace = $modx->evalSnippets("[[".$snippet."]]");
$this->LogSnippet($replace);                                        

// Replace values
$var_search[] = $matches[0][$i];
$var_replace[] = $replace;  

вставляем:

$this->snippetsParsed++;


И наслаждаемся работой плэйсхолдеров. У меня получилось вставлять и пагинацию Ditto, и формы AjaxSearch.
Кому лень исправлять — вот файл phx.parser.class.inc.php, содержащий патч antonkuzmin
  • +2
  • 27 июля 2010, 04:07
  • kpoxas

Комментарии (21)

RSS свернуть / развернуть
0
Интересно.
Насколько надежен способ подсчета количества сниппетов на странице через регулярное выражение?
Скажем, это не нарушит логику, если внутри шаблонов того же Дитто будут стоять вызовы сниппетов?

И еще, я выкладывал сюда решение по доработке кеширования PHx (которое тоже оказалось бажным), может слить эти два патча в один?
avatar

antonkuzmin

  • 29 июля 2010, 09:22
0
Дело в том, что для своих Шаблонов Ditto инициализирует класс pHX отдельно. То есть pHx может парсерить странцу за несколько вызовов. Счетчик при этом сбрасывается.
У меня получалось всегда, что именно плагин запускал класс последним. Но это не догма. Конечно, это дело тестирования.

Кстати про ваше решение: я его туда вроде инсталлировал :) И оно есть в прикрепленном файле.
А на форум разработчикам pHx по-моему бесполезно писать. Может, конечно, я не туда пишу http://modxcms.com/forums/index.php/topic,50281.msg301735.html#msg301735?
avatar

kpoxas

  • 29 июля 2010, 11:50
0
в вашем файле phx.parser.class.inc.php неработающая реализация кеширования («забывает» массив с прокешированными phx-сниппетами).
моя же реализация не просто чинит собственный кеш phx, но заставляет его использовать «общий» кеш сниппетов modx, что, имхо, правильнее.
avatar

antonkuzmin

  • 29 июля 2010, 12:11
0
Секунду… исправил и заменил файл
avatar

kpoxas

  • 29 июля 2010, 12:18
0
есть еще одна существенная недоработка:
если я вызываю такую конструкцию:
[+phx:if=`[*id*]`:is=`81`:then=`
      [[Ditto? &parents=`15` &startID=`15`  &removeChunk=`Comments` &tpl=`ditto_portfolio` &paginate=`1` &extenders=`dateFilter,tagging` &paginateAlwaysShowLinks=`1` &dateSource=`pub_date` &tagData=`partnersTags` &tagDelimiter=`,`  &dateFormat=`%d.%m.%Y` &sortBy=`pub_date` &id=`portfolio2`]]
   `+]

Выполняется 17 запросов к БД не на странице 81!

А при такой:

[+phx:if=`[*id*]`:is=`81`:then=`
      [!Ditto? &parents=`15` &startID=`15`  &removeChunk=`Comments` &tpl=`ditto_portfolio` &paginate=`1` &extenders=`dateFilter,tagging` &paginateAlwaysShowLinks=`1` &dateSource=`pub_date` &tagData=`partnersTags` &tagDelimiter=`,`  &dateFormat=`%d.%m.%Y` &sortBy=`pub_date` &id=`portfolio2`!]
   `+]

всего 4!!!
Есть мнения, как это исправить?

avatar

kpoxas

  • 29 июля 2010, 13:12
0
а сам документ кешируется?
вообще 4 запроса на ресурс — подозрительно мало для дитто.
avatar

antonkuzmin

  • 29 июля 2010, 14:49
0
документ не кэшируется. Но дело не в этом. Он и не должен исполняться.
Дело в том что PhX выполняет сниппет в независимости от того, должен он выводиться или нет
avatar

kpoxas

  • 29 июля 2010, 14:57
+1
я невнимательно прочитал ваш комментарий.
насколько я понимаю устройство modx, кешируемый вызов сниппета отличается от некешируемого только в том случае, когда страница берется из кеша: или результат выполнения сниппета целиком записывается в файл кеша страницы, или там остается только его вызов.

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

хотя если не вдаваться в детали, это определенно баг.
avatar

antonkuzmin

  • 29 июля 2010, 15:57
0
Можно тоже написать патч, чтоб отслеживал условия, и не выполнял сниппеты в условиях
avatar

kpoxas

  • 30 июля 2010, 03:19
0
Ищу решение, чтобы это все работало в случае, если какой-то сниппет содержит чанк, содержащий другой сниппет
avatar

kpoxas

  • 2 августа 2010, 00:40
0
Заменил

if ($this->snippetsParsed > $this->snippetsQuantity || ($this->snippetsQuantity==0) )

на

if (/*$this->snippetsParsed > $this->snippetsQuantity || */($this->snippetsQuantity==0) )

Вроде работает
avatar

kpoxas

  • 2 августа 2010, 01:03
0
у меня такое решение работало при небольшом количестве сниппетов) как только сниппетов на странице набралось десяток, всё вернулось на круги своя.

не имея времени разбираться с принципом работы phx предложил бы такой способ: вбить все известные плейсхолдеры в «исключения»

вот тот самый злополучный кусок кода, который пропускает обработку Jot и Ditto

preg_match_all('~\[(\+|\*|\()([^:\+\[\]]+)([^\[\]]*?|)(\1|\))\]~s', $template, $matches);                               
if ($matches[0]) {
$array_of_useful_tags = array('[+pages+]','[+jot.html.comments+]','[+jot.html.moderate+]','[+jot.html.form+]');
$matches[0] = array_diff($matches[0],$array_of_useful_tags);
$template = str_replace($matches[0], '', $template);
$this->Log("Cleaning unsolved tags: \n" . implode("\n",$matches[2]) );
}

глупо, но действенно)
avatar

simple_dream

  • 4 августа 2010, 19:04
0
Заменил

if ($this->snippetsParsed > $this->snippetsQuantity || ($this->snippetsQuantity==0) )


на

if (/*$this->snippetsParsed > $this->snippetsQuantity || */($this->snippetsQuantity==0) )


Вроде работает

А так делали?
avatar

kpoxas

  • 5 августа 2010, 17:01
0
делал, не помогло…
phx парсил страницу несколько раз, и на последнем разе snippetsQuantity неизменно превращалось в ноль — соответственно условие срабатывало :)
avatar

simple_dream

  • 5 августа 2010, 17:42
0
наверное, сниппет в сниппете был. Еще не нашел, как это побороть
avatar

kpoxas

  • 5 августа 2010, 20:23
0
да, без «сниппетов в сниппете» я себе разработку на modx не представляю)
avatar

simple_dream

  • 6 августа 2010, 14:00
0
Это можно считать рабочим решением? И при этом уже не нужно ждать выполнения снипетов?
avatar

Dronowar

  • 6 августа 2010, 13:10
0
В большинстве случаев срабатывает.
avatar

kpoxas

  • 6 августа 2010, 13:29
0
если вы о моём решении, то оно 100% рабочее, так как действует в лоб) осталось туда только вписать весь список вырезаемых плейсхолдеров
avatar

simple_dream

  • 6 августа 2010, 13:59
0
А куда вставлять:
preg_match_all('~\[(\+|\*|\()([^:\+\[\]]+)([^\[\]]*?|)(\1|\))\]~s', $template, $matches);                               
if ($matches[0]) {
$array_of_useful_tags = array('[+pages+]','[+jot.html.comments+]','[+jot.html.moderate+]','[+jot.html.form+]');
$matches[0] = array_diff($matches[0],$array_of_useful_tags);
$template = str_replace($matches[0], '', $template);
$this->Log("Cleaning unsolved tags: \n" . implode("\n",$matches[2]) );
}

avatar

Dmi3y

  • 20 августа 2010, 17:13
+1
вместо:

preg_match_all('~\[(\+|\*|\()([^:\+\[\]]+)([^\[\]]*?)(\1|\))\]~s', $template, $matches);
                        if ($matches[0]) {
                                $template = str_replace($matches[0], '', $template);
                                $this->Log("Cleaning unsolved tags: \n" . implode("\n",$matches[2]) );
                        }
avatar

kpoxas

  • 20 августа 2010, 19:04

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.