k47.cz    — každý den dokud se vám to nezačne líbit
foto Praha výběr povídky kultura | twitter FB


Nette CachedControl

1. 11. 2008 — k47 (CC by-nc-sa)

Jednoduchá Nette komponenta s integrovaným kešováním.


Když jsem zjistil, že se mi moje naprasené Nette komponenty, které se starají o zdejší patičky a hlavičky a další věcičky, nekešují i když by měli, rozhodl jsem se přijít se sytémovějším řešením. Proto jsem si napsal velice jednoduchou abstraktní komponentu, která kešuje a razantně zeštíhlí zděděné komponenty (někdy i na pár řádek). Je to sice maličkost, ale někomu by se mohla snad hodit.

Tady je celý zdrojový kód (licence je taková ta svobodná):

<?php

abstract class CachedControl extends Control{

  const CACHE_NAMESPACE = 'application/output';
  protected $expire = 1200;
  protected $cacheKey;
  protected $templateFile;
  protected $tags = array();

  abstract function renderContent();
  protected function startup() {}
  protected function addSuffix() { return '';}

  function render() {

    if (isset(Environment::getConfig('app')->cachedControl->expire)) {
      $this->expire = Environment::getConfig('app')->cachedControl->expire;
    }

    $cache = Environment::getCache(self::CACHE_NAMESPACE);
    $this->cacheKey = $this->getClass() . $this->getName() . $this->addSuffix();

    if (isset($cache[$this->cacheKey])) {
      echo $cache[$this->cacheKey];

    } else {
      $this->template->setFile(dirname(__FILE__) .  $this->templateFile);
      $this->template->registerFilter('TemplateFilters::curlyBrackets');

      $this->renderContent();

      echo $content = $this->template->__toString();

      if ($this->expire && $this->expire > 0) {
        $cache->save(
          $this->cacheKey,
          $content,
          array(
            'expire' => $this->expire,
            'tags' => $this->tags,
          )
        );
      }
    }
  }
}

?>

Zděděná komponenta je potom, co se kódu týče, sympaticky skromná. Pohleďte:

<?php

class MenuControl extends CachedControl {
  //adresa šablony vzhledem k umístění komponenty
  protected $templateFile = '/MenuControl.phtml';

  //pole tagů, slouží k invalidaci keše
  protected $tags = array('entry', 'comment');

  public function renderContent(){

    $this->template->menu = MenuSection::findAllAsTree(); //veškerá logika přijde sem

  }
}

Všechno zajímavé přijde do přetížené abstraktní metody renderContent. Tam patří celá logika a k lokální šabloně se odtamtud přistupuje normálně přes

$this->templte->proměnná = 'XYZ';

Komponenta se vykreslí metodou render. V nadřazené šabloně se tedy nejspíš vyskytne něco jako: {? $control->render()}

Expirace keše se dá nastavit členskou proměnnou $expire, nebo globálně v konfiguračním souboru přes klíč app.cachedControl.expire (defaultně je nastaven na 1200, což znamená 20 minut).

Další drobností je metoda addSuffix, která je tu pro případ, že se na stránkách vyskytuje víc různých komponent stejného typu a je nutné je nějak od sebe odlišit. Kdyby tomu tak nebylo, soubor s keší by se u všech komponent jmenoval stejně a pochopitelně by se všude vkládal jeden a ten daný. Používám to třeba při generování výpisů novinek.

Návratová hodnota metody se vloží na konec klíče identifikující keš a tak stačí addSuffix jednoduše přetížit:

protected function addSuffix() {
  return $this->year;
}

a keše výpisů novinek za jednotlivé roky jsou od sebe odděleny, mají na konci jména souboru různý rok a všechno je v cajku.

A to je vše, snad to někomu k něčemu bude.

píše k47 & hosté, ascii@k47.cz