Kešování html výstupu

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

Zdravím,
podle stránky: v dokumentaci jsem si na stránce vytvořil krásné kešování html výstupu. Funguje to tak, že v metodě renderCosi zapnu ob_start() a v metodě shutdown() zavolám ob_get_flush() čímž se dostanu k vygenerovanému výstupu.

Je to krásná metoda, ale má jednu chybu. Nefunguje. V metodě shutdown() ještě výstup nebyl poslán, takže ob_get_flush nic nevrátí. Díval jsem se, že v metodě shutdown() dostanu jako parametr také response, ale pokud se snažím tento response vyrenderovat a uložit, tak se mi do výsledný výstup pěkně zmrší.

Jak se tedy dostat k vygenerovanému kódu stránky, tak abych si ho mohl uložit do cache?

Kenn
Člen | 110
+
0
-

Možnost kešovat je už i přímo v šablonách pomocí bloku {cache}{/cache}. Jenom si nejsem jistý, jak přesně to funguje :)

JajazXbm
Člen | 29
+
0
-

Kešování pomocí bloku {cache} neřeší můj problém, protože se stejně provede metoda renderCosi() a ta trvá dlouho. Vlastní vykreslení šablony je celkem rychlé, proto chci cachovat kompletně celý html výstup. Vzhledem k tomu, že těch render metod mám víc, tak jsem to chtěl dělat globálně jednou metodou a ta stránka z dokumentace vypadala dobře.

Michalek
Člen | 211
+
0
-

https://forum.nette.org/…html-vystupu

Je slíbena úprava pro současnou verzi, taky na to čekám jako na smilování :-) Sám to nejsem schopnej zprovoznit.

JajazXbm
Člen | 29
+
0
-

No já bych věděl jak to vyřešit, sice je to strašně prasácky, ale funguje to. Radši bych nějaké řešení, které nebude tolik prasácké.

protected function shutdown($response)
{
    if(isset($this->cacheKey)){
        $content = (string) $response->getSource();
        $cache = \Nette\Environment::getCache($this->cacheStorage);
        $config = array("expire" => self::CACHE_EXPIRATION);
        $cache->save($this->cacheKey, $content, $config);
	    echo $content; die();
    }
}

Hlavně mi není jasné, proč řádek: $content = (string) $response->getSource(); ve výsledku způsobí, že se potom při finálním vykreslení šablony nepoužije layout.phtml. Při tomto vykreslení se layout vezme v potaz, takže v proměnné $content mám korektně vykreslenou šablonu, ale do prohlížeče se nedostane :(

Editoval JajazXbm (19. 11. 2009 8:33)

martin.majlis
Člen | 1
+
0
-

Jsem se dneska taky zasekl na tom samem problemu – ale ani tvuj trik mi nefungoval, tak jsem zkoukl zdrojaky – a podle mne se to da vyresit takto:

protected function beforeRender() {
	$cache = Environment::getCache('app/out');

	$this->cacheKey = $this->getCacheKey();
	$this->storeToCache = true;

	// ověření, zda je položka v keši
	if (isset($cache[$this->cacheKey])) {
	    echo $cache[$this->cacheKey]; // vypsat a finíto
	    $this->storeToCache = false;
	    $this->terminate();
	}

}

protected function shutdown($response) {
	if ($this->storeToCache) {

	    ob_start();
	    $response->send();
	    $content = ob_get_clean();

	    if ($content) {
		// FIX: Buga v dokumentaci - https://doc.nette.org/cs/caching
		// FIX: Buga na foru - https://forum.nette.org/cs/2982-kesovani-html-vystupu
		$cache = Environment::getCache('app/out');
		$cache->save($this->cacheKey, $content, array(
		    'expire' => 3600 * 24 * 31,
		));
	    }
	}
}

S tim, ze kod z beforeRender muze byt klidne i ve startup.

Vyki
Člen | 388
+
0
-

Super! Jsem si použil myšlenku toho posledního kódu ve svém skriptu s tím, že jsem si to přizpůsobil pro své účely vážně to běhá. Možná by chtělo aby se k tomu vyjádřil David. Už se co řeší celkem dlouho v jiném vlákně a ne jeden člověk na řešení tohoto problému čeká.

JajazXbm
Člen | 29
+
0
-

Musím říct, že to od martin.majlis mně také nefungovalo. Tak jsem zase přemýšlel a hledal jak to zařídit a mám řešení, které mně funguje. Není to nijak čisté, ale mně to funguje.

	protected function cacheStart($storageName, $keyName)
	{
		$this->cacheStorage = $storageName;
		$cache = \Nette\Environment::getCache($this->cacheStorage);

		if(isset($cache[$keyName])){
			$this->cacheStorage = NULL;
			$this->terminate(new \Nette\Application\RenderResponse($cache[$keyName]));
		}
		else{
			$this->cacheKey = $keyName;
		}
	}

	public function terminate(\Nette\Application\IPresenterResponse $response = NULL)
	{
		if (isset($this->cacheKey)) {
			ob_start();
			$response->send();
		$content = ob_get_clean();

		if ($content) {
				$cache = \Nette\Environment::getCache($this->cacheStorage);
				$config = array("expire" => time() + self::CACHE_EXPIRATION, "tags" => array($this->cacheStorage));
				$cache->save($this->cacheKey, $content, $config);
				parent::terminate(new \Nette\Application\RenderResponse($content));
		}
		}
		parent::terminate($response);
	}
MzK
Člen | 127
+
0
-

sry, že otevírám několika letý topic, ale nejsou zde aktuální informace.
V nové verzi nette se změnilo pár metod a přestalo mi Kešování html výstupu fungovat.
V metodě shutdown $content = ob_get_flush(); vrací "", protože ještě nebyla šablona renderována.
zde se o tom něco píše.

Jak tedy skript pro kešování celého výstupu opravit, aby to fungovalo?

Patrik Votoček
Člen | 2221
+
0
-

Možná by stálo za zvážení založit nový topic a tenhle poslat do věčných lovišť ať to zbytečně nemate.

MzK
Člen | 127
+
0
-

Tak mám to takto: funkční řešení.

<?php
public function shutdown($response = null) {
		if ($this->cacheKey) { // chci kesovat
			$response->send(); //vypise obsah hned
			$content = ob_get_flush(); //ziskám vypsaný obsah do proměnné.
//			dump($content); // opravdu tu je
			if ($content) { // mam obsah?
				$cache = Environment::getCache($this->cacheStorage);
				$config = array("expire" => (60 * 60 * 24),); //"tags" => array($this->cacheStorage));
				$cache->save($this->cacheKey, $content, $config);
				//mam ulozeno.
				//parent::sendResponse(new RenderResponse($content)); // neni potreba
				//parent::shutdown($response); // neni potreba
				//echo $response->render(); // neni potreba
			}
		} else {
			parent::shutdown($response);
			//parent::terminate(new RenderResponse($content));//neni potreba, pripadne vyhodi chybu
			//parent::sendResponse($response);//neni potreba, pripadne vyhodi chybu
		}
		die(); // nevim jak jinak na to.
		//pokud by tu nebylo DIE(), tak se mi znova vypíše šablona bez @layout.. jen ten vnitřek. WTF?
	}
?>

Editoval zacatecnik (10. 3. 2011 13:49)

bojovyletoun
Člen | 667
+
0
-

Důvode je zde → tedy po response->send() `volat `unset(this->response). Mimochodem Nette\Application\IPresenterResponse::send() už není bez parametrů

PJK
Člen | 70
+
0
-

Viz komentář pod stránkou

MzK
Člen | 127
+
0
-

To bojovyletoun „tedy po response->send() `volat `unset(this->response)“

<?php
$response->send(); //vypise obsah
unset($this->response);
?>

MemberAccessException
Cannot unset the property DefaultPresenter::$response

uff, nějak mi to stále nejde a zlobí to.
Potřebuji získat stránku do proměnné a to užit do keše.

<?php
$this->template->render(); // musi se volat, aby bylo co ulozit v ob_get_flush
//$response->send(); //alternativa k template->render()
//unset($this->response); //hází mi chybu Cannot unset the property DefaultPresenter::$response
$content = ob_get_flush(); //mam obsah v promenne.
?>

Takto mi to funguje. Bohužel, mi $response->send() nebo template->render() vykreslí {block content} 2×, ještě pod stránku znova. (to se ale do keše neuloží, takže při dalším načtení stránky (už z keše) se zobrazí stránka správně.