Cachování v šablonách – jak na to?
- vraja
- Člen | 6
Krásný den,
mám presenter který vytvoří stránku, výsledný obsah je v podstatě statický a je ho jen třeba jednou za cca 15 minut obnovit.
Chtěl jsem použít cache v šabloně, dle dokumentace se domnívám že by mělo stačit jen obalit šablonu do tagu cache:
{cache $type, expire => '15 minutes'}
{block content}
... nějaký obsah ...
{/block}
{block head}
<style>...</style>
{/block}
{/cache}
Takto nasazeno to ale nehlásí žádnou chybu, obsah se evidentně neukládá do cache, v /temp/cache se žádný soubor nevytvořil.
můžete mě prosím někdo nasměřovat, co je ještě potřeba udělat proto, aby cache v šabloně fungovala ?
S pozdravem Honza Vrána
- Zax
- Člen | 370
@vraja Nespouštěj tu drahou metodu v renderu, ale místo toho si
předej do šablony anonymní funkci, která tu drahou metodu spustí až když
bude potřeba:
$this->template->data = function() {return $this->expensiveMethod();};
{cache}
{$data()}
{/cache}
Nyní se drahá metoda spustí jen poprvé a pak už se vrací jen HTML z cache a k volání se to nedostane.
- greeny
- Člen | 405
A nebo (čti nejlépe) v té „drahé metodě“ místo těch dat budeš pracovat s cachí. Cachování v šabloně je hlavně kvůli generovaní složitého zdrojáku (RSS feedy, sitemap, apod)
Příklad.:
class Model
{
/** @var Cache */
private $cache;
public function __construct(IStorage $storage)
{
$this->cache = new Cache($storage);
}
public function getData()
{
return $this->cache->load('data', function (&$dependencies) {
return $this->getDataFromDb(); // náročná operace
});
}
}
- Jan Mikeš
- Člen | 771
@newPOPE šahání ze šablony na funkce presenteru mi nepříjde úplně čisté
@vraja takto nějak může vypadat použití cache mimo presenter a šablonu (imho je to mnohem čistější řešení, oddělís tím logiku od předávání do šablony a od samotné šablony):
//config.neon
services:
- MyService(@cacheStorage)
// MyService.php
class MyService {
private $cache;
public function __construct($storage)
{
$this->cache = new Nette\Caching\Cache($storage, "MyCustomNamespace");
}
public function getResult($xyz)
{
return $this->cache->load("result-$xyz", function([Nette\Caching\Cache::EXPIRE => '20 minutes']) use($xyz) {
return $this->myExpensiveFunction($xyz);
});
/* lze napsat i takto: */
$data = $this->cache->load("result-$xyz");
if ($data === NULL) {
$data = $this->cache->save("result-$xyz", $this->myExpensiveFunction($xyz), [Nette\Caching\Cache::EXPIRE => '20 minutes'])
}
return $data;
}
public function myExpensiveFunction($xyz)
{
// Random logika
}
// Presenter.php
public function renderDefault()
{
$this->template->data = $this->myService->getResult($abcd);
}
// template.latte
{$data}
Kod jsem netestoval, ale ± by to melo sedet :-) jde spise o to ukazat, jak lze cache vyuzivat
edit: @greeny to stihl napsat rychleji :-)
Editoval Lexi (11. 1. 2016 15:18)
- vraja
- Člen | 6
Krásný den,
Děkuji všem za rady, nakonec my přišlo nejelegantnější použít variantu se službou tak jak ji to tu nastřelil LEXI.
Chápu, že by se data měla cachovat tam kde vznikají, takže v modelu kde je potřeba načíst data, aby všechny volání modelu tyto data mohla použít.
Nicméně chtěl jsme výsledek maximálně nacachovat, aby se při zobrazení provádělo co nejméně kódu.
Aplikace v modelu načítá rssfeed, v prezenteru se ten feed zamíchá a ořízne na tři záznamy, v šabloně se tyto tři záznamy zobrazí.
Protože zobrazování výsledku se děje mockrát a i to míchání není potřeba provádět často, tak mi přišlo nejvhodnější uložit výsledek, a ten jen občas obnovit.
Čily stav, kdy přijdu na stránku, zjistím zda je vysledek v cache a pokud je tak se zobrazí, když ne tak se výsledek vygeneruje.
Protože dle mého názoru se první spouští kód prezenteru, pak by cache asi patřila právě do něj.
S pozdravem Honza Vrána