Jak zjistit v presenteru, jestli je šablona v cache?
- mprokes
- Člen | 10
Mohu poprosit o radu, jakým způsobem otestovat v presenteru, jestli je část šablony v cache? Abych mohl připravovat podklady pro šablonu jen v případě, že tam není, nebo expirovala?
V šabloně:
{cache $id, ...}
...
{/cache}
A v presenteru něco jako
if (isset($cache[$id])) ...;
- net-vor
- Člen | 35
Relativně vyčerpávající odpověď máš v příručce programátora. Jinak kontroluje se to přesně, jak uvádíš:
<?php
$cache['data'] = $nejaka_data;
if (isset($cache['data']))
{
...
}
?>
- arron
- Člen | 464
Pohled do zdrojaku rika, ze tato cache se uklada do jmeneho prostoru
Nette.Template.Cache
. Takze bych si pro zacatek udelal
neco jako
$cache = Environment::getCache('Nette.Template.Cache');
dump($cache);
a uvidis co Ti z toho vyleze. Z toho uz se asi bude dat poznat, jak to spravne testovat :-)
- mprokes
- Člen | 10
arron napsal(a):
…a uvidis co Ti z toho vyleze. Z toho uz se asi bude dat poznat, jak to spravne testovat :-)
Jojo, to už jsem taky zkoušel, vyleze tohle: :-)
Cache(4) ▼ {
"storage" private => FileStorage(3) ▼ {
"dir" private => ".../temp/cache" (62)
"useDirs" private => TRUE
"context" private => Context(3) ▼ {
"registry" private => array(0)
"factories" private => array(1) { ... }
"frozen" private => FALSE
}
}
"namespace" private => "Nette.Template.Cache" (20)
"key" private => NULL
"data" private => NULL
}
Ale stále jsem nepřišel na to, jak získat klíč, pod kterým je onen
kousek šablony kešovaný.
Koukal jsem i jak CachingHelper (& spol.) klíč počítají, že bych si
ho mohl vygenerovat, ale stále doufám, že existuje nějaký jednodušší
způsob, jen mě nenapadá jaký… :-)
- Vyki
- Člen | 388
Asi by to šlo v pohodě udělat takto:
<?php
class MujPresenter extends BasePresenter
{
public function buildData()
{
return MujModel::findById();
}
}
?>
a v šabloně
{cache $cacheId}
{var $data = $presenter->buildData()}
{foreach $data as $row}
<p>{$row}</p>
{/foreach}
{/cache}
Editoval Vyki (9. 11. 2010 15:58)
- arron
- Člen | 464
Vyki napsal(a):
To by urcite slo, ale prijde mi to takove hodne fuj ;-)
Uvazoval bych asi o tom, pouzit nejaky jiny typ cache nez primo v sablone, popripade to nejak nakombinovat (polozil bych si otazku, je pomalejsi pripravit ta data, anebo vygenerovat ten vystup v sablone? a pak bych se podle toho zaridil…).
- mprokes
- Člen | 10
Samozřejmě můžu cachovat data v presenteru a pak při jejich změně invalidovat i šablonu pomocí tagu, ale myslel jsem, že by to takhle bylo elegantnější. Invalidoval bych jen šablonu a na základě toho bych znovu načetl data a cache by figurovala jen na jednom místě.
Význam má pro mě cachování šablony (data získám v tomto případě rychleji), a že bych se při tom nedotazoval zbytečně na data byla jen taková třešnička na dortu. :-)
V každém případě děkuju za reakce, jdu kešovat v presenteru… :-)
- Michalek
- Člen | 211
Já mám tedy makro cache upravené již z kdysi dávno, ale dnes by mělo už fungovat stejně, takže nějak takhle, ne? Kombinace všeho co tady již bylo postupně zmíněno ;-)
template.phtml
{cache 'ukladam'}
neco co cachujeme v sablone
{/cache}
presenter.php
$templateCache = Environment::getCache('Nette.Template.Cache');
if !isset($templateCache['ukladam']) {
// whatever
}
Editoval Michalek (9. 11. 2010 19:01)
- mprokes
- Člen | 10
Michalek napsal(a):
Podobný zápis jsem zkoušel hned na začátku, ale nefunguje – ‚ukladam‘ podle mě není klíč, pouze klíč ovlivňuje (nebo jsem slepej a dělám něco blbě :-) )
btw: Zkusil jsem pořádně otestovat náročnost načítání dat, a zjistil jsem, že se jedná o zanedbatelnou hodnotu, takže budu kešovat pouze šablonu a data budu načítat stále, i když je dále nevyužiju. A vyhnu se tak alespoň problémům s invalidací keše v presenteru, pokud se mi šablona invaliduje automaticky při změně svého obsahu (tenhle problém by nenastal u Vykiho řešní). :-)
Editoval mprokes (9. 11. 2010 21:46)
- arron
- Člen | 464
Porad jsem tak premyslel nad prispevkem od Vikiho, jehoz reseni jsem tak nehezky zdrbnul…a tu me tak napadlo, co takhle do sablony predat nejakou anonymni funkci?
//presenter
$this->template->data = function () { // nejake nacitani dat
return $nactenaData;
}
//template
{cache}
{foreach $data() as $item}
{$item}
{/foreach}
{/cache}
Je to spise takovy pseudokod a nezkousel jsem to v praxi, ale v zasade nevidim duvod, proc by to nemohlo fungovat (jo a diky Viki za inspiraci;-))
A jeste takovy dotaz, ktery mi lezi v hlave uz docela dlouho a ktery se
diky tomuhle vlaknu konecne dostane ven. K cemu vlastne spravne pouzit makro
{cache}
, kdyz pak stejne nacitam zbytecne ta data? Jedine me napada
to cachovat oddelene, ale to zase asi nedava tak uplne smysl… Na co je tohle
makro tedy primarne urcene?
Editoval arron (9. 11. 2010 21:53)
- Vyki
- Člen | 388
arron napsal(a):
A jeste takovy dotaz, ktery mi lezi v hlave uz docela dlouho a ktery se diky tomuhle vlaknu konecne dostane ven. K cemu vlastne spravne pouzit makro{cache}
, kdyz pak stejne nacitam zbytecne ta data? Jedine me napada to cachovat oddelene, ale to zase asi nedava tak uplne smysl… Na co je tohle makro tedy primarne urcene?
Já to používám k cachování menu. Invaluduje so změna v katalogu.
- Filip Procházka
- Moderator | 4668
no to záleží všechno na použití :)
Model::getList() {
return dibi::select('*')->from('articles')->where('blilba = 5');
}
$this->template->data = Model::getList();
{cache md5((string)$data), expire => '+30 minutes'}
{foreach $data as $item} <!-- data se načtou až zde -->
<h2>{$item['title']}</h2>
{/foreach}
{/cache}
Tohle je samozřejmě jedna z cest, jak je čistá posuďte sami, např i to s tou closurou není špatný nápad, ale už to hodně deleguje moc logiky do templaty
Asi by nebylo špatný mít nějaký jednoduchý model, který by se šabloně předal a obaloval by volání takových funkcí
class LogicDelegator extends Nette\FreezableObject
{
private $callbacks = array();
// pokud je objekt zmrazen půjde pouze volat properties a metody
public function __call($method, $callback = NULL)
{
if (is_callable($callback)) {
$this->updating();
$this->callbacks[$method] = $callback;
return $this;
}
return $this->callbacks[$method]();
// pokud je neznámá metoda zavolána s argumentem uložit do $this->callbacks
// pokud je neznámá metoda zavolána bez argumentu a je v poli callbacks tak zavolat a vrátit, jinak vyjímka
}
public function __get($property)
{
// pokud je čteno z neznámé property a je v poli callbacks tak zavolat a vrátit, jinak vyjímka
return $this->callbacks[$property]();
}
public function __set($property, $callback)
{
$this->updating();
// pokud je do neznámé property ukládáno uložit do $this->callbacks
if (is_callable($callback)) {
$this->callbacks[$property] = $callback;
}
}
public function __clone()
{
$this->updating();
}
}
$ld = new LogicDelegator;
$model = new Articles;
$ld->articles(callback($model, 'getArticles')); // $ld->callbacks['articles'] = $callback
$ld->articles = callback($model, 'getArticles'); // $ld->callbacks['articles'] = $callback
// $ld->articles(); // return $ld->callbacks['articles']();
// $ld->articles; // return $ld->callbacks['articles']();
$ld->freeze();
$this->template->data = $ld;
{cache 'articles', expire => '+30 minutes'}
{foreach $data->articles as $article}
{$article['title']}
{/foreach}
{/cache}
gist: https://gist.github.com/670938 :)
Editoval HosipLan (10. 11. 2010 15:49)
- mprokes
- Člen | 10
HosipLan napsal(a):
{cache md5((string)$data), expire => '+30 minutes'} {foreach $data as $item} <!-- data se načtou až zde --> ...
Teda až tady mi docvaklo, že data fetchuju moc brzo,
// takže když v modelu místo
return dibi::select(...)->fetchAll();
// použiju jen
return dibi::select(...);
data si šablona vytáhne sama, a já jí vlastně ani nepotřebuju testovat :-)
{cache $id, expire => '+7 days', tags => array("tag$id")}
{foreach $data as $item} <!-- data se načtou až zde -->
{/foreach}
{/cache}
A při změně dat jí prostě invaliduju tagem
$cache = Environment::getCache('Nette.Template.Cache');
$cache->clean(array(Cache::TAGS => array("tag$id")));
A víc řešit nemusím. Taky mi to mohlo dojít o něco dříve… :-)
Editoval mprokes (10. 11. 2010 23:24)