Jak zjistit v presenteru, jestli je šablona v cache?

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
mprokes
Člen | 10
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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ý… :-)

arron
Člen | 464
+
0
-

Mam obavu, ze na nic rozumnejsiho neprijdeme, protoze v CachingHelper neni zadna podpora
(zatim) pro zjistovani z venku. Takze bych asi zkusil feature request a zatim bych si pro to napsal nejakou vlastni tridu, ktera mi to bude zjistovat:-)

Vyki
Člen | 388
+
0
-

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
+
0
-

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…).

bazo
Člen | 620
+
0
-

a co takto cachovat tie data rovno v presenteri?

mprokes
Člen | 10
+
0
-

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… :-)

redhead
Člen | 1313
+
0
-

Teďka nedávno byl nový commit, kde se přidává magický index if do možností makra {cache}.

{cache ..., if => true/false}

Ale nejsem si jist co dělá. Odhaduju, že vypíná/zapíná kešování. Nemohlo by to pomoct?

Michalek
Člen | 211
+
0
-

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
+
0
-

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
+
0
-

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)

mprokes
Člen | 10
+
0
-

Mě se tohle makro výborně hodí i v této podobě. Vyhnu se tak neustálému pasírování obsahu přes helpery a/nebo texy :-)

Vyki
Člen | 388
+
0
-

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
+
0
-

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
+
0
-

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)