Кэширование в 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); }
Естественно, эти правила можно комбинировать в зависимости от структуры Вашего сайта. Еще лучше не копипастить одинаковый код, а выделить очистку кэша конкретного документа в отдельную функцию. Код будет короче, чище и позволит сосредоточиться на логику работы Вашего сайта и задания конкретных правил очистки кэша
Истории из жизни айти и обсуждение кода.