Дата публикации: 31.07.2014
Версия системы: 2.9.5, TPL-шаблонизатор.
По мотивам рецепта //wiki.umisoft.ru/Кэширование_динамического_многоуровнего_меню.
Отличие: совместимость по параметрам со штатными макросами, использование штатного кеширующего механизма (я у себя тестировал на memcached)
Меню
Динамическое создание меню заметно нагружает систему, особенно, если оно содержит более одного уровня. И если новости и комментарии могут меняться часто, то меню у сайта, как правило, после этапа разработки остается в неизменном виде месяцами. Это можно использовать и снизить нагрузку на сервер (а, следовательно, уменьшить время генерации страницы), сохранив меню в кеш.
Что хочется от макроса: простота, легкость замены на него в уже имеющемся коде.
Ограничение: текущая страница в меню не выделяется. Можно учитывать в ключе и положение посетителя на сайте, чтобы подсвечивать текущий пункт меню, но это усложняет логику генерации ключа, увеличивает количество хранимых результатов и снижает эффективность кеширования. Считаю, что уж если так необходимо выделять текущий пункт, лучше переложить это дело на плечи яваскрипт.
Принцип работы: из переданных параметров, имени класса, имени метода формируем уникальный ключ, по которому результат работы макроса будет идентифицироваться в кеше. Я еще добавил имя хоста, чтобы избежать пересечения в случае, если на этом же сервере будет использоваться такой же макрос на другом сайте (memcached имеет общее хранилище)
Обращаю внимание на константы __CLASS__ и __METHOD__ , в которых содержатся имя текущего класса '__custom_content' и макроса 'menuCache' - два подчерка.
public function menuCache($menu_tpl = "default", $max_depth = 1, $pid = false){
$c = cmsController::getInstance();
$host = $c->getCurrentDomain(); //получаем имя хоста для использования в ключе
$code = md5(__METHOD__.__CLASS__.$host.$menu_tpl.$max_depth.$pid); //формируем ключ
$cacheFrontend = cacheFrontend::getInstance(); //вызываем кеш ЮМИ
if($s = $cacheFrontend->loadData($code)) return $s; //если в нем есть запись с ключом $code, то возвращаем ее
//генерируем меню
$module = $c->getModule('content'); //получили объект класса модуля по имени
$s = $module->menu($menu_tpl, $max_depth, $pid); //вызвали штатный макрос меню
$cacheFrontend->saveData($code, $s, 3600); //сохранили в кеше на полчаса
return $s;
}
Называем макрос сходно со штатным, передаем ему те же параметры и в том же порядке, что и в штатный; это позволит в дальнейшем пройтись автозаменой по всем шаблонам.
Новости
Все то же применимо к макросу вывода лент новостей с тем дополнением, что нужно еще в ключ кеша включить номер страницы.
public function lastlistCache($path = "", $template = "default", $per_page = false, $ignore_paging = false, $sDaysInterval = '', $bSkipOrderByTime = false) {
$module = cmsController::getInstance()->getModule('news');
if(!$per_page) $per_page = $module->per_page;
$month = (int) getRequest('month');
$year = (int) getRequest('year');
$day = (int) getRequest('day');
$host = cmsController::getInstance()->getCurrentDomain();
$code = md5(__METHOD__.__CLASS__.$host.$path.$template.$per_page.$ignore_paging.$sDaysInterval.$bSkipOrderByTime.$month.$year.$day);
$cacheFrontend = cacheFrontend::getInstance();
if($s = $cacheFrontend->loadData($code)) return $s;
$s = $module->lastlist($path, $template, $per_page, $ignore_paging, $sDaysInterval, $bSkipOrderByTime);
$cacheFrontend->saveData($code, $s, 1800);
return $s;
}
Добавлю еще, на этапе отладки бывает необходимо быстро очистить кеш. Это делается методом flush().
Казалось бы, методика найдена: делаешь кеширующую обертку и внутри нее вызываешь штатный макрос. Но тут на пути попался модуль "Баннеры"... Об этом следующая запись.