Exemple #1
0
 /** @return PsProfilerInterface */
 private function getProfiler($profilerId)
 {
     //Не будем выполнять get_file_name($profilerId), так как нужно вернуть профайлер максимально быстро
     if ($this->CAHCE->has($profilerId)) {
         return $this->CAHCE->get($profilerId);
     }
     check_condition($profilerId, 'Profiler id cannot be empty.');
     if (!$this->enabled) {
         return $this->CAHCE->set($profilerId, new PsProfilerEmpty($profilerId));
     }
     $di = $this->getProfilerDi($profilerId);
     $pr = null;
     //Проверим текущий размер профайлера
     if ($di->isMaxSize(ConfigIni::profilingMaxFileSize())) {
         $locked = PsLock::lock(__CLASS__ . "::compressProfiler({$profilerId})", false);
         if ($locked) {
             $this->compressProfiler($di);
             PsLock::unlock();
         } else {
             //Разимер превышен и мы не смогли получить лок для дампа профайлера. Не будем в этот раз вести профайлинг.
             $pr = new PsProfilerEmpty($profilerId);
         }
     }
     return $this->CAHCE->set($profilerId, $pr ? $pr : new PsProfilerImpl($profilerId));
 }
Exemple #2
0
 private function doResizeImpl(DirItem $srcDi, $w, $h)
 {
     $dim = $w . 'x' . $h;
     $cacheKey = md5("[{$srcDi}]:[{$dim}]");
     if ($this->CAHCE->has($cacheKey)) {
         return $this->CAHCE->get($cacheKey);
     }
     $dstDi = DirManager::autogen("images/{$dim}")->cdToHashFolder(null, null, $cacheKey)->getDirItem(null, $cacheKey, SYSTEM_IMG_TYPE);
     if ($dstDi->isImg()) {
         return $this->CAHCE->set($cacheKey, $dstDi);
     }
     if (!$srcDi->isImg()) {
         return $this->CAHCE->set($cacheKey, null);
     }
     PsLock::lockMethod(__CLASS__, __FUNCTION__);
     try {
         if (!$dstDi->isImg()) {
             //Картинка не была пересоздана в другом потоке
             SimpleImage::inst()->load($srcDi)->resizeSmart($w, $h)->save($dstDi, SYSTEM_IMG_TYPE)->close();
         }
     } catch (Exception $ex) {
         PsLock::unlock();
         throw $ex;
     }
     PsLock::unlock();
     return $this->CAHCE->set($cacheKey, $dstDi);
 }
Exemple #3
0
 /**
  * Метод возвращает формы слова во всех падежах
  * 
  * @param type $word
  * @return array - все склонения слова в виде массива, где под индексом 0 - оригинальное значение
  */
 public function getInflections($word)
 {
     $word = PsCheck::notEmptyString(trim($word));
     if ($this->CACHE->has($word)) {
         return $this->CACHE->get($word);
     }
     $this->LOGGER->info();
     $this->LOGGER->info('> Запрошено склонение для слова [{}]', $word);
     //$fileName = iconv('UTF-8', 'cp1251', $word);
     /*
      * Ищем в БД
      */
     $inflections = InflectsBean::inst()->getInflections($word);
     if (is_array($inflections)) {
         $this->LOGGER->info('< Cклонение для [{}] найдено в базе: {}', $word, array_to_string($inflections));
         return $this->CACHE->set($word, $inflections);
     }
     /*
      * Загружаем с сервиса
      */
     $inflections = $this->loadInflectionImpl($word);
     if (is_array($inflections) && count($inflections) == 7) {
         $this->LOGGER->info('< Склонение для [{}] успешно загружено: {}', $word, array_to_string($inflections));
         //Не забудем сохранить полеченное склонение для слова
         InflectsBean::inst()->saveInflections($inflections);
         return $this->CACHE->set($word, $inflections);
     }
     /*
      * Загрузить не удалось, возвращаем балванку
      */
     $inflections = array_fill(0, 7, $word);
     $this->LOGGER->info('< Склонение для [{}] не определено, возвращаем "болванку": {}', $word, array_to_string($inflections));
     return $this->CACHE->set($word, $inflections);
 }
Exemple #4
0
 /**
  * Создание экземпляра класса для сущности фолдинга
  * @return FoldedClass
  */
 public function getEntityClassInst($ident, $cache = true)
 {
     if (!$cache || !$this->INSTS_CACHE->has($ident)) {
         //Получим элемент - класс
         $php = $this->getResourceDi($ident, self::RTYPE_PHP);
         //Проверим, что это - файл
         check_condition($php->isFile(), 'Не найден класс реализации для сущности ' . $this->getTextDescr($ident));
         //Проверим сущность на изменение
         $this->checkEntityChanged($ident);
         //Получим FoldedEntity, так как её потом нужно будет передать в конструктор
         $foldedEntity = $this->getFoldedEntity($ident);
         //Подключим класс, не будем заставлять трудиться класслоадер
         require_once $php->getAbsPath();
         //Построим название класса на основе идентификатора сущности
         $baseFoldedClass = 'FoldedClass';
         $class = $this->ident2className($ident);
         check_condition(PsUtil::isInstanceOf($class, $baseFoldedClass), "Класс для сущности {$foldedEntity} не является наследником {$baseFoldedClass}");
         //Создаём акземпляр
         $inst = new $class($foldedEntity);
         //Отлогируем
         $this->LOGGER->info("Instance of {$class} created.");
         FoldedResourcesManager::onEntityAction(FoldedResourcesManager::ACTION_ENTITY_INST_CREATED, $this, $ident);
         return $cache ? $this->INSTS_CACHE->set($ident, $inst) : $inst;
     }
     return $this->INSTS_CACHE->get($ident);
 }
 /**
  * Основной метод, выполняющий построение контроллера для просмотра постов.
  * Контроллер может быть отображен в двух случаях: 
  * 1. На странице с просмотром всех постов
  * 2. На странице с рубрикой
  * 
  * @return ShowcasesControllerPanel
  */
 private function getScPanel($postType, Rubric $rubric = null)
 {
     $key = $postType . '-' . ($rubric ? $rubric->getIdent() : '');
     if (!$this->CACHE->has($key)) {
         $plugins[] = $this->getBaseControllerIdents();
         if ($rubric) {
             $plugins[] = Mappings::RUBRIC_2_SCCONTROLLERS($postType)->getMappedEntitys($rubric->getIdent());
         }
         $insts = $this->getUserAcessibleClassInsts(to_array_expand($plugins));
         $ctxt = new ShowcasesControllerCtxt($rubric);
         $result = array();
         /** @var ShowcasesControllerItem */
         foreach ($insts as $ident => $inst) {
             $inst->doProcess($ctxt);
             $result[$ident] = $inst;
         }
         $this->CACHE->set($key, new ShowcasesControllerPanel($result));
     }
     return $this->CACHE->get($key);
 }
 /** @return DirItem */
 public final function getUploadedFileDi($uploadId, $userId = null)
 {
     if (!$this->CACHE->has($uploadId)) {
         $this->assertCanUseDb(__FUNCTION__);
         $this->assertAutonomous('файл не может быть загружен из БД');
         $file = UploadsBean::inst()->getFile($this->DBTYPE, $uploadId, $userId);
         $this->LOGGER->info("File [{$uploadId}] loaded from DB for user [{$userId}] ? {}.", var_export($file, true));
         $this->CACHE->set($uploadId, is_array($file) && array_key_exists('name', $file) ? DirItem::inst($file['name']) : null);
     }
     return $this->CACHE->get($uploadId);
 }
Exemple #7
0
 /**
  * Метод возвращает DirItem элемента, содержащего картинку-представление формулы.
  * 
  * @param type $formula - текстовая формула
  * @param type $createIfNotExists - признак, стоит ли пытаться создавать картинку для формулы
  * @return DirItem
  */
 public function getImgDi($formula, $createIfNotExists = true)
 {
     $formula = TexTools::safeFormula($formula);
     if ($this->CACHE->has($formula)) {
         return $this->CACHE->get($formula);
     }
     $hash = TexTools::formulaHash($formula);
     $imgDI = $this->DM->getHashedDirItem(null, $hash, $hash, 'gif');
     if ($imgDI->isImg()) {
         $this->CACHE->set($formula, $imgDI);
         return $imgDI;
     }
     if (!$createIfNotExists) {
         return null;
     }
     //Создаём структуру директорий
     $imgDI->makePath();
     $contents = '';
     //Запрашиваем графическое представление
     $this->PROFILER->start($formula);
     try {
         //TODO - делать это локально, чтобы не зависить от стороннего сервиса
         $handle = fopen('http://latex.codecogs.com/gif.latex?' . rawurlencode($formula), 'r');
         while (!feof($handle)) {
             $contents .= fread($handle, 8192);
         }
         fclose($handle);
         $this->PROFILER->stop();
     } catch (Exception $ex) {
         //Останавливаем профайлер без сохранения
         $this->PROFILER->stop(false);
         //Делаем дамп ошибки
         ExceptionHandler::dumpError($ex, "Tex formula convertation requested for:\n{$formula}");
         //Попытаемся подчистить за собой, если мы что-то создали
         $imgDI->remove();
         //Пробрасываем эксепшн
         throw $ex;
     }
     //Сохраняем картинку в файл
     $imgDI->putToFile($contents);
     //Сохраним текстовое представление
     $this->DM->getHashedDirItem(null, $hash, $hash, 'gif.tex')->putToFile($formula);
     $this->CACHE->set($formula, $imgDI);
     return $imgDI;
 }
 /**
  * Метод возвращает сущность фолдинга по заданному коду
  * 
  * @return FoldedEntity Сущность, соответствующая заданному коду
  */
 public function getFoldedEntityByDbCode($code)
 {
     return $this->CACHE->has($code) ? $this->CACHE->get($code) : $this->CACHE->set($code, FoldedStorageInsts::getFoldedEntityByUnique(FoldingBean::inst()->getUniqueByCode($code)));
 }
Exemple #9
0
 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));
 }