Pořadí spouštění metod presenteru: Shutdown vs Render šablony

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

Ahoj, podle tohoto obrázku bych si myslel, že:

  1. Proběhne vyrenderování šablony
  2. Spustí se metoda presenter->shutdown()

Ale není tomu tak. Možná proběhne kompilace šablony, ale určitě ne její spuštění (vyrenderování). Mám takovýto kód:

class MyPresenter extends BasePresenter
{
	public function shutdown($response)
	{
		parent::shutdown($response);
		echo "shutdown";
	}

	public function callMeFromTemplate()
	{
		echo "template";
	}
}

A k tomu šablonku:

{block content}
{$presenter->callMeFromTemplate()}

No a oproti mojemu očekávání je ve výstupu nejdříve „shutdown“ a potom teprve „template“. Myslel jsem si, že hraje roli nějaké zachytávání výstupu v šabloně a jeho vypsání až na konci, ale i když obě echa v debuggeru označím breakpointem, nejdříve se provede ten v shutdown a teprv pak až ten ze šablony?

O co se tedy snažím:

V šabloně vypisuju nějaké propertky modelu, které se lazy způsobem inicializují. Tzn. např $object->lastDisplayed obsahuje nějaké datum, kdy byl objekt naposledy vykreslený a tato metoda dělá něco takového: $this->lastDisplayed = Date(); $this->persist(); return $this->lastDisplayed.

Používám Doctrine a v průběhu běhu skriptu persistuju objekty na úrovni Doctrine a až na konci jedinkrát zavolám $documentManager->flush(), což zapíše všechny změny do databáze. A toto mám právě v presenter->shutdown. Datum se v šabloně správně zobrazí, do databáze se nezapíšou, páč se $object->getLastDisplayed() ještě nespustilo a pořadí spuštění kódu je tedy:

$documentManager->flush();
$object->lastDisplayed = Date();
$documentManager->persist($object);

Stručně řečeno potřebuji spustit nějaký kód na konci běhu skriptu, kdy už je celá šablona vykreslená. Takže:

$object->lastDisplayed = Date();
$documentManager->persist($object);
$documentManager->flush();

Co dělám špatně? Jak to udělat lépe? Pomohlo umístění $documentManager->flush() na konec www/index.php, ale mi přijde dost nepěkné.

Díky :-)

Editoval josef.sabl (30. 5. 2016 17:29)

jiri.pudil
Nette Blogger | 1028
+
+2
-

V první řadě bych tam hledal problém v návrhu: šablona je od toho, aby věci vykreslila, ne aby měnila vnitřní stav entit. Ten lastDisplayed můžeš aktualizovat třeba zrovna v render* metodě. Pokud není možné zasáhnout do tohohle, aspoň trošičku méně nepěkné řešení je navěsit to na Application::$onShutdown.

josef.sabl
Člen | 153
+
0
-

jiri.pudil napsal(a):

V první řadě bych tam hledal problém v návrhu: šablona je od toho, aby věci vykreslila, ne aby měnila vnitřní stav entit. Ten lastDisplayed můžeš aktualizovat třeba zrovna v render* metodě. Pokud není možné zasáhnout do tohohle, aspoň trošičku méně nepěkné řešení je navěsit to na Application::$onShutdown.

Hmm, Application::$onShutdown jsem přehlídl, zkoušel jsem Presenter::$onShutdown a ten se taky spouští brzy. Díky.

K té výtce k návrhu:

Jasně, tušil jsem, že součástí odpovědi bude něco takového :)

Je to složitější a hraje tam roli několik věcí: MongoDB, Doctrine, Cachování v šablonách, Lazy loading a inicializace objektů a cílem tohohle návrhu je maximální optimalizace počtu dotazů do databáze a taky celková velikost databáze.

Představ si aplikaci, která pracuje s obrovským množstvím objektů, které mají velké množství properties, které mají náhodnou povahu a v praxi se jich většina nevyužije. Je možné je tedy inicializovat a do databáze uložit až v okamžiku, kdy se na ně uživatel poprvé podívá v UI.

Ale co se týká podstaty dotazu, tak tam jde pouze o to: Jak spustit kód až úplně na konci běhu aplikace. Ten můj use case byl jen pro ilustraci :)

Editoval josef.sabl (1. 6. 2016 15:18)