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 | 211
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 | 667
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ě.