Kešování html výstupu

- JajazXbm
 - Člen | 29
 
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?

- JajazXbm
 - Člen | 29
 
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 | 212
 
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
 
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
 
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.

- JajazXbm
 - Člen | 29
 
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
 
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.
I 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
 
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
 
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 | 668
 
Důvode je zde
→ tedy po response->send() `volat `unset(this->response).
Mimochodem Nette\Application\IPresenterResponse::send()
už není bez parametrů

- MzK
 - Člen | 127
 
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ě.