Использование кэша в OpenCart позволяет сократить количество обращений к базе данных и увеличить быстродействие магазина, однако есть некоторые нюансы в работе самого кэша.
Управление кэшем происходит в файле
./system/library/cache.php, если обратить внимание на функцию get, то видно, что результат возвращается функцией
php unserialize когда файл кэша есть и
null, когда его нет. Это значит, что если в кэше сохранён результат пустой выборки в одной из моделей, то при очередном запросе кэша будет возвращён ноль.
Практически во всех моделях условие проверки кэша следующее:
$product_data = $this->cache->get( ...
if (!$product_data) { ...
что в корне неверно, так как содержание кэша, например, строка s:1:"0";, может сообщить модулю об его "отсутствии" и будет выполнено повторное обращение к базе.
Если создать новые категории, то это будет хорошо заметно. Товаров нет, каждый раз запрос из базы возвращает пустой результат и сохраняет его в кэше. В этом конкретном примере необходимо открыть файл
./catalog/model/catalog/product.php найти функцию
getTotalProducts и в её теле заменить условие
if (!$product_data) { ...
на
if ($product_data === null) { ...
Теперь существование кэша будет правильно воспринято отдельно взятой функцией того или иного модуля. Исправления актуальны для всех версий OpenCart, включая последнюю v1.5.5.1.
Update
Работая с библиотекой кэша
./system/library/cache.php обратил внимание, что принцип выдачи кэшированной информации организован неверно. Модулю, запросившему кэш, может быть выдана устаревшая информация, если обратите внимание на код, то данные с файла считываются раньше проверки на время.
Дабы не создавать отдельную статью, приведу решение здесь. Функцию get() необходимо заменить на код ниже.
public function get($key) {
$data = null;
$files = glob(DIR_CACHE . 'cache.' . preg_replace('/[^A-Z0-9\._-]/i', '', $key) . '.*');
if ($files) {
for ($n=0, $lenght = count($files); $n < $lenght; $n++) {
$file = $files[$n];
$time = substr(strrchr($file, '.'), 1);
if ($time < time()) {
if (file_exists($file)) { unlink($file); }
} elseif (!$n) { $cache = file_get_contents($file); $data = unserialize($cache);
} } } return $data; }
Кстати, обновлённная функция работает немного быстрее, т.к. используется цикл for next (призываю использовать в PHP вместо foreach везде) и
unserialize выполняется не по умолчанию, а только если кэш не устарел.