Vyrenderovaný kód komponenty

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

Zdravím,

potřeboval bych v prezenteru sestavit vlastní odpověď (JSON) a k tomu potřebuji získat pro každou komponentu její vyrenderovanou HTML podobu – tu pak prohnat json_encode() a celé to poslat na výstup. Jak získám onu vyrenderovanou podobu? Nějak to jít musí, protože snippety se také vyrenderují a poté zakódují. Pomohlo by nějak např. obalit HTML každé komponenty značkou {snippet}?

(Snippety jako takové z určitých důvodů nemohu použít.)

Editoval jtousek (12. 12. 2009 10:03)

Ondrej
Člen | 110
+
0
-

jtousek napsal(a):

Zdravím,

potřeboval bych v prezenteru sestavit vlastní odpověď (JSON) a k tomu potřebuji získat pro každou komponentu její vyrenderovanou HTML podobu – tu pak prohnat json_encode() a celé to poslat na výstup. Jak získám onu vyrenderovanou podobu? Nějak to jít musí, protože snippety se také vyrenderují a poté zakódují. Pomohlo by nějak např. obalit HTML každé komponenty značkou {snippet}?

(Snippety jako takové z určitých důvodů nemohu použít.)

ob_start();
$component->render();
$html = ob_get_contents();
$json = json_encode($html);
jtousek
Člen | 951
+
0
-

Ondrej napsal(a):

ob_start();
$component->render();
$html = ob_get_contents();
$json = json_encode($html);

jj to mě taky napadlo, jen jsem myslel, že v nette je na to lepší řešení
No nic. Použiju tedy tohle. :)

Tomik
Nette Evangelist | 485
+
0
-

Takže máš nějaký objekt, komponentu, ta dědí od Control, aby se tento control mohl vykreslit, pokud jej uvedeš do šablony jako {control Neco}, pak musí objekt, který je vytvořen v createComponentNeco, mít metodu render. Ta ovšem rovnou vypisuje, takže si udělej další metodu, např. renderJSON, s tím rozdílem, že ta nebude vypisovat, ale vracet přes return. Tu metodu pak budeš volat, když budeš chtít data pro JSON.

Trochu problém je se šablonama, který rovnou vypisujou, to je dá vyřešit přes ob_start a ob_clean.

Snad to takhle stačí, kdybys to chtěl podrobnějš, ukaž nějaké ukázky kódu.

Edit: Takhle to dopadá, když má člověk vlákno otevřené dlouho a pak až odpovídá. :)

Tomik
Nette Evangelist | 485
+
0
-

jtousek napsal(a):

jj to mě taky napadlo, jen jsem myslel, že v nette je na to lepší řešení

Není.

No nic. Použiju tedy tohle. :)

Použij.

jtousek
Člen | 951
+
0
-

Tomik:
jj dík, jsem si právě říkal že s těma šablonama to bude problém když to nevracej ale rovnou vypisujou… ještě že mám ob… :D

Honza Kuchař
Člen | 1662
+
0
-

udělej další metodu, např. renderJSON

Já mám skoro u každé komponenty 2 metody:

  1. $control->render(); – vypíše na výstup
  2. $control->__toString(); – což je magická metoda, díky které potom když napíšeš echo $control; se ti vypíše klasicky na výstup.

Jsou 2 možnosti na implementaci:

  1. Klasické render(), které normálně odesílá na výstup + __toString(), které zachytává výsledek render() přes OB a vrací jej
  2. Mám __toString(), které vrací string a metodu render, které má v sobě akorát echo $this->__toString(); nebo echo $this; (s druhou metodou nastává problém, pokud vyletí výjimka, proto interně v aplikacích, raději používej __toString())
Výhody a nevýhody řešení a)
  • Výkonné render()
  • Více znovupoužitelné (__toString() můžu dát do nějakého BaseControl) a možná snáze pochopitelné
  • méně výkonné __toString()
Výhody a nevýhody řešení b)
  • Rychlejší __toString()
  • render() má větší náročnost na paměť
jtousek
Člen | 951
+
0
-

honzakuchar:

Přiznám se, že úplně nechápu jak by možnost b fungovala. Pokud komponenta ke svému vykreslení využívá šablonu (což některé mé komponenty využívat budou) tak to bez OB asi nepůjde:

<?php

class SomeComponent extends BaseControl {

	public function render() {
		$this->template->render(); //používá echo a je void => musím využít OB
	}

}

?>
Ola
Člen | 385
+
0
-

Nějak takhle:

<?php
class SomeControl extends Control
{
	public function render()
	{
		echo $this->__toString();
	}

	public function __toString()
	{
		$template = $this->template;
		...
		return $template->__toString(); // nebo return (string)$template;
	}
}
?>

Editoval Ola (12. 12. 2009 17:24)

jtousek
Člen | 951
+
0
-

Ola:

Jak jsem si myslel – $template->__toString(); stejně vnitřně využívá OB a volá render takže se tím vlastně vůbec nic nezmění. Je úplně jedno kde se to OB použije. Navíc kvůli nemožnosti vyhazování výjimek nemam rád metodu __toString().

Panda
Člen | 569
+
0
-

Řešení a) jde napsat elegantněji…

Mám společného předka komponent, kde definuji metody render() a __toString(), které jen obalují příslušné metody objektu Template. Současně si také nadefinuji prázdnou metodu beforeRender (tento název jsem zvolil kdysi dávno a není úplně nejšťastnější), kterou v konkrétní komponentě překryji a bude obsahovat jen definice pro šablonu, nikoliv její konečné vyrenderování.

<?php
abstract class TemplateControl extends Control
{
	protected function beforeRender()
	{
	}

	public function render()
	{
		$args = func_get_args();
		call_user_func_array(array($this, 'beforeRender'), $args);
		$this->template->render();
	}

	public function  __toString()
	{
		$args = func_get_args();
		call_user_func_array(array($this, 'beforeRender'), $args);
		return $this->template->__toString();
	}
}

class MyControl extends TemplateControl
{
	public function beforeRender()
	{
		// ...
	}
}
?>

Konkrétní komponenta pak bude méně ukecaná a obejdu se bez čachrování s OB. Ze všech postupů mi navíc přijde nejpochopitelnější, protože se to principem mírně přibližuje k presenteru – tam také v nějaké metodě jen cpu data do presenteru a o vykreslení samotné šablony se nestarám. Ještě více přiblížit by to šlo automatizací výběru šablony, aby si člověk mohl odpustit volání $template->setFile() (konkrétní kód uveřejním na požádání).

Jinak jak již jtousek předeslal, tak u řešení b) je __toString() stejně výkonné, jako __toString() u řešení a) (echo → output buffer), jen ten render() je zpomalený (echo → output buffer → echo).

Vyki
Člen | 388
+
0
-

Zdravím,
nešlo by náhodou k tomuto účelu použít https://api.nette.org/…esponse.html ?
viz tento příspěvek: https://forum.nette.org/…i-presenteru?…

Editoval Vyki (13. 12. 2009 13:03)