Vyrenderovaný kód komponenty
- jtousek
- Člen | 951
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
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);
- Tomik
- Nette Evangelist | 485
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á. :)
- Honza Kuchař
- Člen | 1662
udělej další metodu, např. renderJSON
Já mám skoro u každé komponenty 2 metody:
$control->render();
– vypíše na výstup$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:
- Klasické
render()
, které normálně odesílá na výstup +__toString()
, které zachytává výsledekrender()
přes OB a vrací jej - Mám
__toString()
, které vrací string a metodu render, které má v sobě akorátecho $this->__toString();
neboecho $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éhoBaseControl
) 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
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
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)
- Panda
- Člen | 569
Ř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
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)