MODX

Cache MODX Revolution -> быстрее только на html

Cache MODX Revolution -> быстрее только на html

Идеального ничего не бывает.
Зачастую у нас в сайтах очень много статических страниц и даже если страницы в кэше, вы можете посмотреть, сколько у нас инклудиться файлов, просто создайте плагин и на событие OnHandleRequest вставьте код:

if ($modx->context->key == 'mgr') break;
print_r(get_declared_classes());
die;
Я не буду говорить, что это самый классный способ, про который я сейчас расскажу, он сырой - но рабочий. Просто делюсь, возможно кому-то и понадобиться.>
Для эксперемента нашего так-же я установил пакет Todc.Bootstrap (можно Bootstrap или просто сами стилить будете, на скорость не влияет)
В самом шаблоне Todc.Bootstrap я закооментил тег $Todc.Scripts ([[-$Todc.Scripts]]), так как нам для эксперемента они не нужны и в чанке Todc.Navbar удалил Breadcrumbs.
Создаём контейнер для вывода к примеру новостей и сами новости (я создал для эксперемента три новости)
в документе конейнере ставим вызов getResources:
[[getResources? &tpl=`multTplgetResources` &includeContent=`1`]]
и шаблон, чанк multTplgetResources:
<code><article class="blog-article">
    <div class="row">
      <div class="span9">
      <div class="blog-content">
        <div class="blog-content-title">
        <h2><a href="[[+uri]]" class="invarseColor">[[+pagetitle]]</a></h2>
        </div>
        <div class="clearfix">
          <ul class="unstyled blog-content-date">
            <li class="pull-left"><i class="icon-calendar"></i>[[+publishedon:strtotime:date=`%d %B, %Y`]]</li>
            <li class="pull-left"><i class="icon-pencil"></i> <a href="#">[[+createdby:userinfo=`fullname`]]</a></li>
          </ul>
        </div>
        <div class="blog-content-entry">
          <p>[[+content:ellipsis=`400`]]</p>
          <a href="[[+uri]]">Contunie →</a>
        </div>
      </div><!--end blog-content-->
    </div><!--end span5-->
</div><!--end row-->
</article></code>
В футер. чанк Todc.Footer вставил вывод времяни:
<span class="debug"><small>Processing Time: <span>[^t^] </span></small></span>
Наполнили внутреннии ресурсы текстом. Проверяем, с кэша примерно выходит около 0,0463 s . Вроде не плохо, но если глянуть даже в сам APC кэш, то хитов и размер файлов нашей странички среди файлов модекса как иголка в стоге сена.

Ну попробуем по эксперементировать, т.е. я не буду сейчас расписывать выборку ресурсов, которые нам нужно кэшировать нашим способом, а которые пропускать. Просто поэксперементируем.
Итак. создаём плагин myCache, ставим галочку на событие OnWebPagePrerender и вставляем код (если у нас в плагине одно событие. не обязательно использовать $modx->event->name, но у нас ещё будут события, поэтому пока оставим так.):

switch ($modx->event->name) {
	case 'OnWebPagePrerender':
	$file_cache = false;
	// аолучаем с конфига параметры
	$cache_prefix = $modx->getOption('cache_prefix');
	$cache_handler = $modx->getOption('cache_handler');
	// формируем ключ кэша
	$file = md5($_SERVER['REQUEST_URI']);
	// формируем путь для нашего кэша
	$arrayUrl = array_filter(explode('/',$_SERVER['REQUEST_URI']),function($el){ return !empty($el);});
	$pathUri = implode('/',$arrayUrl);
	$cache_path = 'static/'.$pathUri;
	// проверяем какой кэш и существует ли файл в кэше
	switch ($cache_handler) {
		case 'cache.xPDOAPCCache':
			if(apc_exists($cache_path.'/'.$cache_prefix.$file)) {
				$file_cache = true;
			}
		break;
		case 'xPDOFileCache':
			if(file_exists(MODX_CORE_PATH.'cache/'.$cache_path.'/'.$file.'.cache.php')) {
				$file_cache = true;
			}
		break;
	}
	// если файла нету в кэше и кэш у нас активный, то пишем вывод в кэш
	if($file_cache == false && $modx->getCacheManager()) {
		$output = &$modx->resource->_output;
		$time = time();
		$cacheArray = array('output'=>$output, 'time'=>$time);
		$modx->cacheManager->set($file,$cacheArray,0,array(
		xPDO::OPT_CACHE_KEY => $cache_path,
		xPDO::OPT_CACHE_HANDLER => $modx->getOption('cache_resource_handler', null, $modx->getOption(xPDO::OPT_CACHE_HANDLER)),
        xPDO::OPT_CACHE_FORMAT => (integer) $modx->getOption('cache_resource_format', null, $modx->getOption(xPDO::OPT_CACHE_FORMAT, null, xPDOCacheManager::CACHE_PHP)),
		));

	}
	break;
}
Т.е. мы сохранили вывод страницы в свой кэш, в качестве ключа использовал урл страницы, я эксперементировал только c:
  • xPDOFileCache — стандартный обработчик по умолчанию, хранит кэш в файлах.
  • cache.xPDOAPCCache — обработчик для расширения php-apc (не забудьте создать префикс с ключом cache_prefix в системных настройках)
Теперь, создадим в корне нашего сайта файл read_cache.php и вставим код:
<!--?php 
  // функция для вывода времяни (можно не использовать)
  function microtime_float() {
      list($usec, $sec) = explode(" ", microtime());
      return ((float)$usec + (float)$sec);
  }
  // функция извлечения массива с файла
  function geFile($key) {
    $value= null;
    if (file_exists($key)) {
      if ($files = @fopen($key, 'rb')) {      
        if (flock($files, LOCK_SH)) {
          $value= @include $key;
          flock($files, LOCK_UN);
            if ($value === null) {
                fclose($files);
                @ unlink($key);
            }
        }
        @fclose($files);
      }
    }
    return $value;
  }
  // стартуем
  $time_start = microtime_float();
  // Получаем название ключа для кэша
  $file = md5($_SERVER['REQUEST_URI']);
  // формируем путь для нашего кэша
  $arrayUrl = array_filter(explode('/',$_SERVER['REQUEST_URI']),function($el){ return !empty($el);});
  $pathUri = implode('/',$arrayUrl);
  if(strlen($pathUri) --> 0) $pathUri .= '/'; 
  // достаём с кэша конфиг файл 
  $system_cache_pach = MODX_CORE_PATH.'cache/system_settings/config.cache.php';
  $valueFile = geFile($system_cache_pach);  
  // берём с настроек модекса префикс кэша и время жизни кэша
  $cache_prefix = $valueFile['cache_prefix'];
  $cache_expires = intval($valueFile['cache_expires']);
  // проверяем. если есть файл в кэше
  switch ($valueFile['cache_handler']) {
    case 'cache.xPDOAPCCache':      
      $cache_key = "static/$pathUri$cache_prefix$file";
      // проверяем, есть ли файл в кэше
      if(apc_exists($cache_key)) {
        // получаем файл с кэша
        $value = apc_fetch($cache_key);
        // Если его время жизни ещё не прошло или cache_expires у нас нуль, то выводим
        if ((time() - $cache_expires) < $value['time'] || $cache_expires == 0) {
            // подсчитываем время
            $time_end = microtime_float();
            $time = $time_end - $time_start;
            // парсим наш тег [^t^] и заменяем на время
            echo str_replace('[^t^]', 'APCCache: '.round($time,6).' s', $value['output']); // Выводим содержимое файла  
            exit;
        } else {
          // удаляем файл кэша
          apc_delete($cache_key);
        }
      }               
    break;
    case 'xPDOFileCache':
      $cache_file = MODX_CORE_PATH."cache/static/$pathUri$file.cache.php"; 
      // проверяем, есть ли файл в кэше
      if (file_exists($cache_file)) {
        // получаем наш файл
        $value = geFile($cache_file);
        // Если его время жизни ещё не прошло или cache_expires у нас нуль, то выводим
        if ((time() - $cache_expires) < $value['time'] || $cache_expires == 0) {
            // подсчитываем время
            $time_end = microtime_float();
            $time = $time_end - $time_start;
            // парсим наш тег [^t^] и заменяем на время
            echo str_replace('[^t^]', 'FileCache: '.round($time,6).' s', $value['output']); // Выводим содержимое файла  
            exit;
        } else {
          // удаляем файл с кэша
          unlink($cache_file);
        }
      }
    break;
  }
Подключаем наш файл в index.php примерно после строчки 39, после инклуда конфига:
  .......
  /* this can be used to disable caching in MODX absolutely */
$modx_cache_disabled= false;

/* include custom core config and define core path */
@include(dirname(__FILE__) . '/config.core.php');
if (!defined('MODX_CORE_PATH')) define('MODX_CORE_PATH', dirname(__FILE__) . '/core/');

// Пытаемся вывести содержимое кэша
require_once "read_cache.php"; 

/* include the modX class */
.......
Очищаем кэш, и пробуем. Первый вызов как обычно без кэша, а второй и последующий Processing Time: APCCache: 0.0004 s - 0.0005 s . Не плохо?

Но это ещё не всё, нам же нужно управлять нашим кэшем, а вернее, при создание или редактирование ресурса, нам нужно убивать кэш редактируемого ресурса и кэш нашего родителя. про это, если будут интерестно в следующий раз. А может кто и сам продолжит и предложит свои варианты. Буду рад.

Код не вылизанный, просто наброски для эксперемента, чтобы увидеть результат.

Посмотреть в реальности можете по адресу http://talks.artdevue.com/test-multilanguage/ (возможно работать и не будут, так как это тестовый сайт, может кто и успеет увидеть). Там правда вывод идёт с мультиязычностью, об этом тоже напишу топик и выложу код.
В кратце про мультиязычность: Это расширение, в админке добавляете нужные языки указывая к каким контекстам они активны. Для каждого языка можно добавить свои параметры (как в контекстах).
При создании ресурса, у вас будет вкладка для переводов. Всё подгоняеться под стандартные расширение, такие как Wayfinder, getResources, getPage.... т.е. никаких изминений в них не нужно делать.

Valentin Rasulov

4 Комментария

Jn Ruslan # (комментарий был изменён) 2014-02-08 00:38:00
Спасибо! Очень интересная статья. Всё в принципи доходчиво. Единственно чего я ЧАЙНИК не понял так это
«не забудьте создать префикс с ключом cache_prefix в системных настройках».
Если можно поподробней вот на этом месте. Как создаётся префикс и с чем его едят. Спасибо!
Valentin Rasulov Автор # (комментарий был изменён) 2014-02-11 23:46:19
Если у Вас файловый кэш, то префикс не обязательно создавать, так как весь кэш хранится в директории сайта.
Если вы используете не файловый а общий кэш (APC и т.д.), тогда нужно создать префикс, который будет идентифицировать ваш сайт в общей системе кэширования.
Как создаётся префикс
Система -> Настройка
Фильтр по разделу — выбираем "Кеширование"
Ищем Ключ — cache_prefix
Если его нет, создать
Ключ: cache_prefix
Тип поля: текстовое поле
Пространство имён: core
Запись словаря для раздела: caching
Значение: ваш_префикс
А Александр # 2015-09-09 22:00:49
вот вопрос LikeDislike
модуль то недоработан ибо я захожу с разных браузеров и голосую по несколько раз
Брежнев Иван # 2015-09-09 22:17:52
Нужно включить опцию защиты от повторных голосований по IP
Чтобы оставить комментарий необходимо авторизоваться