MODX конечно крутая CMF, но порой сталиваешся с такими мелочами, которые напрягают. Я не буду в этом топике плакаться какие все вокруг плохие, а я такой хороший. Возьмем, например, ветку Revolution и препарируем ее. А чтобы вы не потеряли интерес к этой заметке, вот небольшой план статьи:
- Разбор бэкенда
- Углубление в настройки
- Работа с вложенными чанками
- Наблюдаем за работой парсера
- Мощный кеш
Удаление параметра из набора параметров
Создаем набор параметров. В него добавляем Х параметров, а потом понимаем, что мы разошлись. Пытаемся найти кнопку удалить…
В общем у меня ничего не вышло. Пришлось искать другой способ удаления параметра.
Решение проблемы: открываем на редактирование ненужный параметр и полностью копируем все данные другого нужного параметра (якобы пытаясь перезаписать старый параметр новыми данными).
Следствие: Можем перезаписать значение нужного параметра.
Значения ключей в настройках контекстов
Смоделируем такую ситуацию: несколько контекстов, к каждому контексту привязаны свои настройки.
Если в админке несколько сайтов, то как правило в настройках контекста переопределяют такой ключик, как site_name. А теперь представьте, ваша фирма всегда позиционировала свое название как Крутые{Перцы}.
Как вы думаете, какой результат мы увидим во front-end? Правильно, просто Крутые.
Решение проблемы: вместо скобок использовать специальные символы.
А что делать тем, кто у кого используется 1 шаблон на нескольких контекстах и желает в качестве ключа указать некий набор параметров для JS кода? Там специальные символы не помогут и одним чанком не обойтись.
Тут решений уже два
- Первое решение: создать свой сниппет и в зависимости от контекста отдавать нужный чанк посредством getChunk.
- Второе решение: Для каждого контекста создать свой чанк и в шаблоне вместо ключа прописать [[$name_[[*context_key]]]]. Но как бы там нибыло, данная запись выглядит вырвиглазно… Спасибо artdevue за данное решение.
Работа с вложенными чанками
В MODX еще с давних пор есть такая функция, как
public function getChunk($chunkName, array $properties= array ()) {
$output= '';
if (array_key_exists($chunkName, $this->sourceCache['modChunk'])) {
$chunk = $this->newObject('modChunk');
$chunk->fromArray($this->sourceCache['modChunk'][$chunkName]['fields'], '', true, true);
$chunk->setPolicies($this->sourceCache['modChunk'][$chunkName]['policies']);
} else {
$chunk= $this->getObject('modChunk', array ('name' => $chunkName), true);
if (!empty($chunk) || $chunk === '0') {
$this->sourceCache['modChunk'][$chunkName]= array (
'fields' => $chunk->toArray(),
'policies' => $chunk->getPolicies()
);
}
}
if (!empty($chunk) || $chunk === '0') {
$chunk->setCacheable(false);
$output= $chunk->process($properties);
}
return $output;
}
А теперь давайте создадим простой
<?php
ini_set("display_errors",1);
$data='';
$phs=isset($phs)?explode(",",$phs):array();
if(isset($tpl,$phs) && $tpl!='' && count($phs)>0){
foreach($phs as $item){
$data.=$modx->parseChunk($tpl,array('item'=>$item,'time'=>time()));
}
}
return $data;
установим phpthumbof и создадим
<p><b>[[+time]]</b>: [[+item]] - [[!phpthumbof? &input=`[[+item]]` &options=`&h=150&f=jpg`]]</p>
Сделаем вызов этого всего на странице примерно так: [[!test? &tpl=`test` &phs=`/assets/1.jpg,/assets/2.jpg`]]
Но вот незадача, при первом вызове в сниппет phpthumbof приходит строка [[+item]] и только при всех последующих уже распарсеный плэйсхолдер
Решение: Хранить такие проблемные чанки в файлах. Т.е. поставить галочку статичный и выбрать файл
Еще одно решение от bezumkin: Заменить parseChunk на getChunk.
Наблюдаем за работой парсера
Эксперимент проведем следующим образом: создадим новый документ с шаблоном blank. Содержимое и все остальное оставим пустым. Проверим, что стоит галочка кешировать.
public function processElementTags($parentTag, & $content, $processUncacheable= false, $removeUnprocessed= false, $prefix= "[[", $suffix= "]]", $tokens= array (), $depth= 0) {
$this->_processingTag = true;
$this->_processingUncacheable = (boolean) $processUncacheable;
$this->_removingUnprocessed = (boolean) $removeUnprocessed;
$depth = $depth > 0 ? $depth - 1 : 0;
$processed= 0;
$tags= array ();
/* invoke OnParseDocument event */
$this->modx->documentOutput = $content;
$this->modx->invokeEvent('OnParseDocument', array('content' => &$content));
$content = $this->modx->documentOutput;
unset($this->modx->documentOutput);
if ($collected= $this->collectElementTags($content, $tags, $prefix, $suffix, $tokens)) {
$tagMap= array ();
foreach ($tags as $tag) {
$token= substr($tag[1], 0, 1);
if (!$processUncacheable && $token === '!') {
if ($removeUnprocessed) {
$tagMap[$tag[0]]= '';
}
}
elseif (!empty ($tokens) && !in_array($token, $tokens)) {
$collected--;
continue;
}
if ($tag[0] === $parentTag) {
$tagMap[$tag[0]]= '';
$processed++;
continue;
}
$tagOutput= $this->processTag($tag, $processUncacheable);
if (($tagOutput === null || $tagOutput === false) && $removeUnprocessed) {
$tagMap[$tag[0]]= '';
$processed++;
}
elseif ($tagOutput !== null && $tagOutput !== false) {
$tagMap[$tag[0]]= $tagOutput;
if ($tag[0] !== $tagOutput) $processed++;
}
}
$this->mergeTagOutput($tagMap, $content);
if ($depth > 0) {
$processed+= $this->processElementTags($parentTag, $content, $processUncacheable, $removeUnprocessed, $prefix, $suffix, $tokens, $depth);
}
}
$this->_processingTag = false;
return $processed;
}
перед строкой
$this->_processingTag = true;
добавим
static $test; echo ++$test."<br />";
Ну и открываем в браузере нашу страницу. о0! число 1..2..3 Спрашивается какого мать вашу… Пустая страница. Что там парсить? Смотрим внимательно исходник
$this->modx->invokeEvent('OnParseDocument', array('content' => &$content));
Таким образом даже на пустой странице мы вызываем 3 раза одно и тоже событие. Мне страшно подумать, что будет с теми сайтами, у которых еще на это событие повешан какой-то код.
artdevue для эксперимента проверил сколько раз будет выполняться данная функция при различных условиях. таким образом мы имеем следующую табличку.
Условие | Итераций |
---|---|
[[snippet]] | 2 |
{{$chunk}} | 2 |
Пустая страница | 3 |
[[num?input=`1000`]] | 5 |
[[*pagetitle:num]] | 6 |
[[num?input=`[[*pagetitle]]`]] | 7 |
Несуществующий сниппет | 23 |
Несуществующий чанк | 23 |
Мощный кеш
На одном из рабочих сайтов открыл я папку с кешем и чуть со стула не упал. 1 страница в кеше занимает от 50 до 200 КБ. Нет, это может конечно и нормально, но кеш обновляется при каждом изменении документов. Обновил 1 документ — все закешированные страницы удалились. А если 100 страниц? 1000? Это уже на несколько МБ тянет. А если новости добавляются каждый день?
P.S. Переименовал топик, чтобы выглядело менее плаксиво и вызывающе
Автор: Agel_Nash