public function hasAll(array $keys) { return array_has_all_keys($keys, $this->data); }
public function getFromCache($id, $group, $REQUIRED_KEYS = null, $sign = null) { $cacheId = $this->localCacheKey($id, $group); //Сначала ищем в локальном хранилище if ($this->CACHE->has($cacheId)) { $CACHED = $this->CACHE->get($cacheId); if ($CACHED['sign'] == $sign) { $this->LOGGER->info("Информация по ключу '{$cacheId}' найдена в локальном кеше"); return $CACHED['data']; } else { $this->LOGGER->info("Информация по ключу '{$cacheId}' найдена в локальном кеше, но старая и новая подписи не совпадают: [{}]!=[{}]. Чистим...", $CACHED['sign'], $sign); $this->CACHE->remove($cacheId); $this->CACHELITE->remove($id, $group); return null; } } /* * Самое интересное и спорное место всей реализации. * Нам нужно отслеживать свежесть кешей. Сами по себе они сбрасываются через опередённое время (время жизни кеша). * Но это время достаточно велико и, если мы сейчас, например, правим код, то нам некогда ждать, пока всё само сабой обновится. * * Кеши валидируются через свои, so called, "подписи". * Например - структура проекта (строка навигации) зависит от кол-ва постов в каждом разделе, но при этом если какой-либо пост изменится, то * на подпись кеша для навигации это никак не повлияет, а ведь в посте мог измениться анонс, например. * * Всё крутится вокруг изменения сущностей фолдингов. При изменении сущности будет сброшен кеш, который от этого фолдинга зависит. * Весь вопрос в том - как отслеживать эти изменения?.. Единственное решение - пробегать по всем фолдингам и выполнять checkAllEntityChanged. * Решение это довольно дорогостоящее. Даже если сущность не изменилась и кеш не будет перестроен, мы вынуждены выполнить очень много действий. * * Есть два варинта для обеспечения "свежести" кешей: * * Вариант №1. * Каждый раз при запросе кеша выполнять checkAllEntityChanged для фолдингов, от которых зависит запрашеваемая группа кешей. * Это нам ВСЕГДА обеспечит свежесть всех кешей, но данная операция является довольно тяжёлой. * * Вариант №2. * Выполнять проверку checkAllEntityChanged для всех фолдингов, но так как это довольно дорого - делать это не каждый раз, а с определённой периодичностью. * Это также обеспечивает свежесть кешей, но операция - очень тяжёлая, поэтому её нельзя выполнять каждый раз. * В идеале её вообще должен выполнять внешний процесс, запускаемый раз в EXTERNAL_PROCESS_CALL_DELAY минут. * Будем эмулировать его работу посредством класса ExternalProcess. * В продакшене будет работать второй вариант - там частота обновлений кешей не так важна. */ $this->validateGroup($group); PsProfiler::inst(__CLASS__)->start('LOAD from cache'); $CACHED = $this->CACHELITE->get($id, $group); PsProfiler::inst(__CLASS__)->stop(); if (!$CACHED) { $this->LOGGER->info("Информация по ключу '{$cacheId}' не найдена в кеше"); return null; } if (!is_array($CACHED)) { $this->LOGGER->info("Информация по ключу '{$cacheId}' найдена в хранилище, но не является массивом. Чистим..."); $this->CACHELITE->remove($id, $group); return null; } if (!array_has_all_keys(array('data', 'sign'), $CACHED)) { $this->LOGGER->info("Информация по ключу '{$cacheId}' найдена в хранилище, но отсутствует параметр sign или data. Чистим..."); $this->CACHELITE->remove($id, $group); return null; } if ($CACHED['sign'] != $sign) { $this->LOGGER->info("Информация по ключу '{$cacheId}' найдена в хранилище, но старая и новая подписи не совпадают: [{}]!=[{}]. Чистим...", $CACHED['sign'], $sign); $this->CACHELITE->remove($id, $group); return null; } $MUST_BE_ARRAY = is_array($REQUIRED_KEYS); $REQUIRED_KEYS = to_array($REQUIRED_KEYS); if ($MUST_BE_ARRAY || !empty($REQUIRED_KEYS)) { //Если нам переданы ключи для проверки, значит необходимо убедиться, что сами данные являются массивом if (!is_array($CACHED['data'])) { $this->LOGGER->info("Информация по ключу '{$cacheId}' найдена в хранилище, но не является массивом. Чистим..."); $this->CACHELITE->remove($id, $group); return null; } foreach ($REQUIRED_KEYS as $key) { if (!array_key_exists($key, $CACHED['data'])) { $this->LOGGER->info("Информация по ключу '{$cacheId}' найдена, но в данных отсутствует обязательный ключ [{$key}]. Чистим..."); $this->CACHELITE->remove($id, $group); return null; } } } $this->LOGGER->info("Информация по ключу '{$cacheId}' найдена в хранилище"); //Перенесём данные в локальный кеш для быстрого доступа return array_get_value('data', $this->CACHE->set($cacheId, $CACHED)); }