Кэширование в Modx Revo
Если Вы сделали несколько сайтов на Modx, то скорее всего уже сталкивались с проблемой кэширования и корректной очистки кэша. Ниже показывается, как работает кэш Modx и как создать плагин для очистки кэша одного ресурса.
Файловый кэш по умолчанию в Modx Revo работает не всегда так, как нам хочется. Что именно не так?
За кэширование документов в Modx отвечают 2 галочки на вкладке Настройки. Если отмечена галочка "Кэшируемый", а она отмечена по умолчанию, то при первом обращении к документу для него сохранится кэш в файле, из которого чтение будет происходить заметно быстрее. Если, конечно, у Вас не статичная страничка с чистым html. Отметив галочку "Очистить кэш", мы задаем принудительную очистку для того, чтобы при следующем обращении к ресурсу кэш пересоздался заново, и посетители сайта увидели сделанные нами изменения.
Проблема заключается в том, что при сохранении документа очищается весь кэш на сайте, а не того документа, изменения в котором мы делали. Если у нас небольшой сайт-визитка с малым временем генерации страниц, то на работу сайта это критично не скажется. Но если у нас ресурс побольше с несколькими сотнями тяжелых страниц, генерация которых занимает по 2-3 секунды, то гроханье всего кэша при правке небольшой опечатке в одной статье становится большой роскошью.
Все, что нам нужно, это создать плагин для очистки кэша конкретного ресурса при сохранении документа. При этом кэш других документов должен оставаться нетронутым. Решение подсмотрено у Василия Безумкина и немного расширено под наши нужды.
Итак, сам плагин. Нужно создать его под любым именем и назначить ему системные события OnDocFormRender и OnDocFormSave. На первом событии мы отключаем параметр "Очистить кэш". Можете убедиться в этом, включив плагин и открыв в админке любой документ - галочка будет снята. Второе событие вызывает код, очищающий кэш текущего документа.
switch($modx->event->name) {
case 'OnDocFormRender':
$resource->set('syncsite', 0);
break;
case 'OnDocFormSave':
if ($modx->event->params['mode'] != 'upd') {return;}
$resource->_contextKey = $resource->context_key;
$cache = $modx->cacheManager->getCacheProvider($modx->getOption('cache_resource_key', null, 'resource'));
$key = $resource->getCacheKey();
$cache->delete($key, array('deleteTop' => true));
$cache->delete($key);
break;
}
Все работает отлично! Но теперь давайте посмотрим чуть дальше.
Допустим, у нас есть раздел "Все новости" на сайте, где транслируются заголовки и аннотации самих новостей. При сбросе кэша конкретной новости нужно еще "обнулить" и раздел "Все новости", ведь мы не обязательно будем править текст в поле content, а можем поменять pagetitle или introtext. Соответственно, кроме сброса кэша самого сохраняемого ресурса нужно еще сбросить другую страницу. К тому же, у нас могут быть и другие "сборные" страницы, которые работают по такому же принципу. Настроить очистку кэша для таких страниц несложно, нужно всего лишь дописать в наш плагин, в case OnDocFormSave несколько строк.
Давайте посмотрим на таком примере.
Предположим, у нас есть раздел "Все новости" с id=10, "Статьи" с id=15 и "Конкурсы" с id=50 .
Сами новости имеют шаблон template=5.
Плюс есть карта сайта (не путайте с sitemap.xml), где транслируются те же новости с id=100.
Рассмотрим 2 варианта:
1. При редактировании отдельной новости, статьи или конкурса нужно очистить кэш соответствующих страниц-родителей
// Ищем родителя сохраняемого ресурса
$parent_id = $resource->get('parent');
// Проверяем, наш ли это документ
if(in_array($parent_id, array(10, 15, 50)))
$res=$modx->getObject('modResource', $parent_id);
$cache = $modx->cacheManager->getCacheProvider($modx->getOption('cache_resource_key', null, 'resource'));
$res->_contextKey = $res->context_key;
$key = $res->getCacheKey();
$cache->delete($key, array('deleteTop' => true));
$cache->delete($key);
}
2. Очищаем кэш карты сайта при редактировании новости - документа с шаблоном=5
// Если редактируем страницу с указанным шаблоном
if($resource->get('template') == 5) {
// Получаем документ - карту сайта и очищаем его уже известным кодом
$res = $modx->getObject('modResource', 100);
$cache = $modx->cacheManager->getCacheProvider($modx->getOption('cache_resource_key', null, 'resource'));
$res->_contextKey = $res->context_key;
$key = $res->getCacheKey();
$cache->delete($key, array('deleteTop' => true));
$cache->delete($key);
}
Естественно, эти правила можно комбинировать в зависимости от структуры Вашего сайта. Еще лучше не копипастить одинаковый код, а выделить очистку кэша конкретного документа в отдельную функцию. Код будет короче, чище и позволит сосредоточиться на логику работы Вашего сайта и задания конкретных правил очистки кэша
Истории из жизни айти и обсуждение кода.