Блочное кэширование html-кода в XSLT

Материал из Umicms
Перейти к:навигация, поиск

В данной статье будет приведен пример небольшого кастомного php-макроса, с помощью которого можно закэшировать определенный html-блок сайта, допустим список разделов каталога. В стандартном xsl шаблоне происходит начальный вызов, xsl:apply-templates, потом полученные xml-данные обрабатываются, далее происходят дополнительные вызовы для получения необходимых данных. Для очень высоко нагруженного сайта, одним из идеальных вариантов было бы кэширование не xml-данных, которые потом еще надо обработать, а итогового html-кода, одного из блоков страницы сайта. Рассмотрим пример метода для реализации нашей задачи:

public function categoryCache(){

  $xsltDom = new DomDocument;
  $xsltDom->resolveExternals = true;
  $xsltDom->substituteEntities = true;
  // $filePath - путь к xsl-шаблону трансформации.
  $filePath = CURRENT_WORKING_DIR . '/xsltTpls/leftCache.xsl';
  $xsltDom->load($filePath, DOM_LOAD_OPTIONS);
  
  $xslt = new xsltProcessor;
  $xslt->registerPHPFunctions();
  $xslt->importStyleSheet($xsltDom);
  
  $dom_new = new DOMDocument("1.0", "utf-8");
  // $xml - xml-данные для трансформации.
  $xml = file_get_contents('udata://catalog/getCategoryList/void/shop/');
  $dom_new->loadXML($xml);
  
  //производим трансформацию
  $result = $xslt->transformToXML($dom_new);
  //html-данные необходимо включить в CDATA и в какой либо корневой узел.
  $result = '<udata><![CDATA[' . $result . ']]></udata>';
  
  // данный принцип возвращения данных отключает xslt-трансформацию системой UMI.CMS
  return array('plain:result' => $result);

}


Метод можно добавить в файл classes/modules/custom.php, тогда вызов в xsl-шаблоне будет следующим:

<xsl:value-of select="document('udata://custom/categoryCache?expire=36000')/udata" disable-output-escaping="yes" />

Полученный html-код будет закэширован на час, если на сайте включен кэш. В случае необходимости, можно настроить сохранение кэша в текстовый файл на сервере, как это было сделано в данной статье Кэширование результата работы метода getCreateForm в XSL-шаблоне . Пример метода, для кэширования данных в html-файл:

public function getCategoryListCustom(){
      $folder = CURRENT_WORKING_DIR . '/sys-temp/udatacache/';  
      $path = $folder . 'left-columnCache.xml';
      if(!is_dir($folder)) mkdir($folder, 0777, true);
      if(is_file($path)) $mtime = filemtime($path);
      $expire = 86400;
     
      if(!is_file($path) || time() > ($mtime + $expire)) {
        $xsltDom = new DomDocument;
        $xsltDom->resolveExternals = true;
        $xsltDom->substituteEntities = true;
        // $filePath - путь к xsl-шаблону трансформации.
        $filePath = CURRENT_WORKING_DIR . '/xsltTpls/modules/catalog/leftCache.xsl';
        $xsltDom->load($filePath, DOM_LOAD_OPTIONS);

        $xslt = new xsltProcessor;
        $xslt->registerPHPFunctions();
        $xslt->importStyleSheet($xsltDom);
       
        $dom_new = new DOMDocument("1.0", "utf-8");
        // $xml - xml-данные для трансформации.
        $xml = file_get_contents('udata://catalog/getCategoryList/void/shop/');
        $dom_new->loadXML($xml);
       
        //производим трансформацию
        $result = $xslt->transformToXML($dom_new);
        //html-данные необходимо включить в CDATA и в какой либо корневой узел.
        $result = "<udata mode=\"cache\"><![CDATA[" . $result . "]]></udata>";
        file_put_contents($path, $result);

        // данный принцип возвращения данных отключает xslt-трансформацию системой UMI.CMS
        return array('plain:result' => $result); 
      }else{
        $result = file_get_contents($path);
        return array('plain:result' => $result);
      }	
  }


Пример шаблона leftCache.xsl:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xsl:stylesheet SYSTEM "ulang://i18n/constants.dtd:file">

  <xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:xlink="http://www.w3.org/TR/xlink" 
  xmlns="http://www.w3.org/1999/xhtml" 
  xmlns:umi="http://www.umi-cms.ru/TR/umi">
    
    <xsl:output encoding="utf-8" method="html" indent="yes"/>
    
    <xsl:template match="/">
      <xsl:apply-templates select="." mode="left-column" />
    </xsl:template>
    
    <xsl:template match="udata[@method = 'getCategoryList']" mode="left-column">
      <ul class="catalog_menu" umi:button-position="bottom left" umi:element-id="{@category-id}" umi:region="list" umi:module="catalog" umi:sortable="sortable">
        <xsl:apply-templates select="//item" mode="left-column" />
      </ul>
    </xsl:template>
    
    <xsl:template match="udata[@method = 'getCategoryList']//item" mode="left-column">
      <li umi:element-id="{@id}" umi:region="row">
        <span>
          <a href="{@link}" umi:field-name="name" umi:delete="delete" umi:empty="&empty-section-name;">
            <xsl:value-of select="." />
          </a>
        </span>
        <xsl:apply-templates select="document(concat('udatacache://catalog/getCategoryList/void/', @id))/udata"/>
      </li>
    </xsl:template>
    
    <xsl:template match="udata[@method = 'getCategoryList']">
      <ul umi:element-id="{@category-id}" umi:region="list" umi:module="catalog" umi:sortable="sortable" umi:button-position="top right">
        <xsl:apply-templates select="//item" />
      </ul>
    </xsl:template>
    
    <xsl:template match="udata[@method = 'getCategoryList']//item">
      <li umi:element-id="{@id}" umi:region="row">
        <a href="{@link}" umi:field-name="name" umi:delete="delete" umi:empty="&empty-section-name;">
          <xsl:value-of select="." />
        </a>
      </li>
    </xsl:template>
    
  </xsl:stylesheet>