Informace o přihlášeném uživateli v Control – komponentě
- motorcb
- Člen | 552
Zdravím.
Jak bych měl zobrazit informace o přihlášeném uživateli v komponentě?
<?php
namespace MyApp;
use Nette;
use Nette\Application\UI\Multiplier;
use Nette\Application\UI\Form;
class OpravneniControl extends Nette\Application\UI\Control
{
public function __construct()
{
echo "*".$this->context->user->getId()."*";
}
public function render()
{
$this->template->setFile( __DIR__ . '/Test.latte' );
$this->template->render();
}
}
Co byste doporučili?
- DI – nevím jak ?
- předávat si id přihlášeného uživatele do konstruktoru ?
- ZZromanZZ
- Člen | 87
Dávám jenom lehký nástin řešení
Konstruktor a metoda render třídy OpravneniControl:
<?php
public function __construct(\Nette\ComponentModel\IContainer $parent, $name)
{
parent::__construct($parent, $name);
}
public function render()
{
$this->template->setFile( __DIR__ . '/Test.latte' );
// napr. jako promenna v sablone
$this->template->userID = $this->presenter->user->getId();
$this->template->render();
}
?>
Továrna někde například v presenteru:
<?php
protected function createComponentOpravneni($name) {
return new OpravneniControl($this, $name);
}
?>
P.S. Píšu z hlavy, tak to ber s rezervou.
Editoval ZZromanZZ (6. 3. 2013 16:07)
- ViPEr*CZ*
- Člen | 817
motorcb napsal(a):
ZZromanZZ:
Díky, ovšem to moc dobře nechápu.. K čemu je to proměnná $name?
Na jméno komponenty. Jde to taky napsat takto třeba:
protected function createComponentOpravneni() {
return new OpravneniControl($this, "opravneni");
}
Editoval ViPEr*CZ* (6. 3. 2013 16:32)
- Majkl578
- Moderator | 1364
Tak tak, jen je potřeba si dávat pozor a předávat si v konstruktoru instanci na Presenter, ve kterém komponentu vytvářím!
Neblábol tu. Předávat do konstruktoru instanci presenteru a název komponenty není nutné, dokonce se to dnes ani běžně nedělá a konstruktor se používá čistě pro předávání závislostí.
- Filip Procházka
- Moderator | 4668
Všechno špatně !!!
komponenta správně:
class TestControl extends Nette\Application\UI\Control
{
public function __construct()
{
parent::__construct(); // není potřeba předávat rodiče, stačí ho zavolat
}
public function render()
{
$this->template->setFile( __DIR__ . '/Test.latte' );
$this->template->render();
}
}
šablona komponenty správně:
{$user->id}
presenter
protected function createComponentTest()
{
return new TestControl();
}
Všechny komponenty (které jsou připojeny k presenteru) a presentery,
mají automaticky v šabloně proměnnou $user
, která je
instancí Nette\Security\User
a poskytuje data o uživateli, která si do ní uložíš.
- ViPEr*CZ*
- Člen | 817
Majkl578 napsal(a):
Tak tak, jen je potřeba si dávat pozor a předávat si v konstruktoru instanci na Presenter, ve kterém komponentu vytvářím!
Neblábol tu. Předávat do konstruktoru instanci presenteru a název komponenty není nutné, dokonce se to dnes ani běžně nedělá a konstruktor se používá čistě pro předávání závislostí.
A v komponentě, když pak zavoláš $this->getPresenter(); dostaneš
instanci presenteru? Já myslím, že to vrací NULL ne? Nebo nějaká nová
magie o které zase nevím a píše se o ní jen na githubu? Rozhodně nechci
blábolit… spousty věcí si nepamatuji z hlavy.
To, že UI\Component má ve své šabloně instanci na usera je druhá
věc ;-)
Editoval ViPEr*CZ* (6. 3. 2013 17:29)
- Majkl578
- Moderator | 1364
ViPErCZ napsal(a):
A v komponentě, když pak zavoláš $this->getPresenter(); dostaneš instanci presenteru? Já myslím, že to vrací NULL ne?
Ano i ne, pokud je v tu chvíli již připojena k Presenteru,
NULL
vracet nebude. Akce závislé na jeho existenci je vhodné
dát do attached metody popř. někam, kde víš, že už attached bude (metoda
render).
- Majkl578
- Moderator | 1364
ZZromanZZ napsal(a):
A co když usera potřebuješ již v konstuktoru nějaké komponenty? Tak jsem pochopil původní otázku.
Konstruktor by měl být co nejjednodušší a pouze inicializovat stav objektu. Uvedenou logiku, jako nějaké předávání dat šabloně, je vhodné dělat později, buď ve chvíli připojení k Presenteru (metoda attached) nebo ideálně až v render metodě.
- ViPEr*CZ*
- Člen | 817
Majkl578 napsal(a):
ViPErCZ napsal(a):
A v komponentě, když pak zavoláš $this->getPresenter(); dostaneš instanci presenteru? Já myslím, že to vrací NULL ne?
Ano i ne, pokud je v tu chvíli již připojena k Presenteru,
NULL
vracet nebude. Akce závislé na jeho existenci je vhodné dát do attached metody popř. někam, kde víš, že už attached bude (metoda render).
Co to je zase za magii? Zase mi něco uniká. Jsem zvyklý předávat parametry, které mi nabízí IDE. Při vytváření potomka ze třídy Control se mi automaticky generuje konstruktor, který má parametry parent a name. Jestli tedy dobře chápu jde o trochu více psaní v mém případě. V tom Vašem musím navíc znát životní cyklus komponenty a tedy vědět kdy se spouští attached?
Nabízí se mi dvě otázky. Jednak zda-li je v plánu měnit konstruktor… tj. jeho parametry nebo můj zápis je prostě o více psaní jen? A druhá. Jak to je vlastně s takovou komponentou formuláře? Tam se taky dostane presenter přes attached?
- ZZromanZZ
- Člen | 87
Viz uplně můj první příspěvek …
V konstruktor po zavolání konstruktoru rodiče již máš připojený rodičovský presenter.
public function __construct(IContainer $parent, $name)
{
parent::__construct($parent, $name);
Debugger::barDump($this->presenter->user);
}
Ale zvaž co říkali kluci. Že logiku vyčleníš mimo konstruktor, bude to nejspíše rozumnější.
Editoval ZZromanZZ (6. 3. 2013 17:56)
- David Matějka
- Moderator | 6445
**@ViPEr\*CZ\***: ve zkratce: kdyz potrebujes komponentu (treba pres $this[‚komponenta‘] nebo v template {control komponenta}) zavola se Nette\ComponentModel\Container::getComponent() to se postara o zavolani createComponent($name) metody (ktera potom zavola prislusnou createComponent$name() metodu) odkud ziska vytvorenou komponentu, potom se do aktualni komponenty (presenteru) prida do seznamu komponent vytvorena komponenta pres Nette\ComponentModel\Container::addComponent() tahle metoda nove vytvorene komponente nastavi rodice – tzn. aktualni komponentu (napr. Presenter) – pres Nette\ComponentModel\Component::setParent() a tahle metoda zavola refreshMonitor metodu, ktera potom zavola attached metodu :)
a imho rvani parametru do konstruktoru pri vytvareni komponenty muze
zpusobit problemy, protoze addComponent
se vola jen v pripade, ze parent neni nastaven – uz se zavola
z konstruktoru.. ale to asi taky neni idealni
podrobneji v https://doc.nette.org/…n/components#…
Editoval matej21 (6. 3. 2013 18:31)
- Vojtěch Dobeš
- Gold Partner | 1316
Dovolím si k diskusi doporučit můj článek: https://pla.nette.org/…nty-k-rodici.
Jinak znalost metody attached
není nějaké tajné knowhow
z Githubu, ale jde o základní věc ve světě Nette komponent (formuláři
počínaje). Attached je dobrý přítel :).
- ViPEr*CZ*
- Člen | 817
Sedím celej tento hezkej den u kompu, tak možná už z cesty. Ale proč
už třída Nette\Application\UI\Control nepřepíše třeba konstruktor a
nechá mě přes IDE vytvořit konstruktor, kterej se vezme až z té
hierarchie z abstraktní třídy Nette\ComponentModel\Component, která navíc
je abstraktní a měla by sloužit jako model odvozených potomků?
A ty mi tady teď říkáš, že tam (předpokládám parent a name) cpát
nemám? Trochu divoký i na mě.
Navíc se podívej prosím na toto: https://api.nette.org/…ent.php.html#43
Když si nastavíš parametry (o kterých předpokládám, že jsi psal, že
můžou působit problémy), tak se ti addComponent zavolá tady. Tj. prosím
odpověď na moje otázky. To co psal @matej21 je mimo mísu.
- ViPEr*CZ*
- Člen | 817
vojtech.dobes napsal(a):
Dovolím si k diskusi doporučit můj článek: https://pla.nette.org/…nty-k-rodici. Jinak znalost metody
attached
není nějaké tajné knowhow z Githubu, ale jde o základní věc ve světě Nette komponent (formuláři počínaje). Attached je dobrý přítel :).
Díky to už dává smysl. Bylo by super na toto odkázat v klasické
dokumentaci, kde se píše o tvorbě komponenty. To „magický“ připojení
přes attached jsem už také kdysi vyzkoušel. Jen jsem se lekl, že předávka
v konstruktoru je totálně blbě, když na mě vybafnul @Majkl578.
Už jsem si udělal čas i na Formy. Jelikož předávku dělám přes
konstruktor, tak u nich jsem to nevěděl (rozhodně né z hlavy). Ale mrknul
jsem teď do API, tak vidím, že tam se to taky attachne. ;-)
- David Matějka
- Moderator | 6445
**ViPEr*CZ***: j to addComponent se zavola, mam to v tom prispevku opraveny :)
ja osobne jsem snad nikdy nepouzil $parent a $name pri inicializaci a
nechavam to na component modelu.
ted uz vlastne ani nemuzu, protoze pro kazdou komponentu mam factory, ktera se
napr. postara o zavislosti, takze inicializuju komponentu uz tam a k rodici
nemam pristup..
- Vojtěch Dobeš
- Gold Partner | 1316
Abych v tom trošičku udělal jasno (možná to jen já nedokážu z tohoto vlákna jasně vyčíst):
V případě vlastní vizuální komponenty (tedy dědící od
Nette\Application\UI\Control
) platí, že:
- konstruktor může obsahovat cokoli, nejlépe ale nic
- jakýkoliv kód zavislý na presenteru by se měl odpíchnout z metody
attached
: ta je zavolána neznámo kdy, ale určitě v pravý čas, a bude v ní presenter k dispozici (při správnéinstanceof
kontrole předaného$parent
) - některé služby jsou v šabloně automaticky dostupné (např.:
$user
) - připojení k rodiči se už dávno nemusí dělat přes konstruktor (ačkoliv kvůli zpětné kompatibilitě to stále jde), mnohem hezčí způsob je vrácení z továrničky (rodič a jméno jsou přiřazeny automaticky)
Editoval vojtech.dobes (6. 3. 2013 19:04)
- Vojtěch Dobeš
- Gold Partner | 1316
motorcb Funguje to takto:
protected function attached($parent)
{
parent::attached($parent);
if ($parent instanceof Nette\Application\UI\Presenter) {
$this->presenter === $parent // TRUE
$user = $this->presenter->user // ...
}
}
- Vojtěch Dobeš
- Gold Partner | 1316
Ta otázka mě to trochu děsí :). Není to best-practice, je to prostě
podmínka. $user
je v presenteru, musím tedy hlídat, jestli jsem
byl připojen právě k němu. Bůhví, k čemu jinému bude ta komponenta
jednou připojena…
Můžeš to otočit, pokud !instanceof
, tak
return;
, abys nemusel mít většinu kódu v ifu.
- Vojtěch Dobeš
- Gold Partner | 1316
Do attached směřovat to, co je závislé na presenteru (redirecty,
parametry atd.). jasir má samozřejmě pravdu, že instanci
Nette\Security\User
je mnohem lepší injektovat jako každou jinou
závislost.
- ViPEr*CZ*
- Člen | 817
vojtech.dobes napsal(a):
Do attached směřovat to, co je závislé na presenteru (redirecty, parametry atd.). jasir má samozřejmě pravdu, že instanci
Nette\Security\User
je mnohem lepší injektovat jako každou jinou závislost.
Tak tak, tím se zbavím vlastně přímý závislosti na Presenteru.
Komponenta bude mít vstříknutou závislost na Nette\Security\User, která je
pro ní životně důležitá. Pak bych ovšem raději (kvůli tomu, že nevím
jestli parent je Presenter) nastavil šabloně proměnnou user. Je to možná
z hlediska použitelnosti nejprůhlednější řešení.
Ovšem momentální uspořádání podle mě nebrání ničemu mít jako
nejvyššího parenta právě Presenter (i když je to tfuj závislost navíc),
protože sám Presenter vystupuje jako komponenta a komponenty mají metodu
lookup, která si ho na tom vrcholu najde (je mi jasné, že se tak děje
z nějakého interního důvodu a rozhodně závislost na Presenteru není moc
hezká… ale přímo v dokumentaci to pro laika nenajdu).
Btw. teď třeba čtu v dokumentaci https://doc.nette.org/…n/components
že není třeba sample na to, jak si udělat komponentu formuláře (najdu ho
třeba v quickstartu, tak tam dejme třeba odkaz aspoň). Ale hned nahoře je
odstavec Šablony a v něm je hned kec. Protože komponenta Form nemá továrnu
na šablonu.
- Vojtěch Dobeš
- Gold Partner | 1316
ViPErCZ
- formulář je komponenta
- obvykle nevytváříme komponentu formuláře (v Nette už je hotová)
- závislost na presenteru není nic tfuj, je to architektura Nette – presenter je vždy nejvyšší rodič komponentové struktury
- vůbec ten tvůj poslední odstavec nechápu – v Quickstartu se žádná komponenta formuláře nepíše
- ViPEr*CZ*
- Člen | 817
vojtech.dobes napsal(a):
ViPErCZ
- formulář je komponenta
- obvykle nevytváříme komponentu formuláře (v Nette už je hotová)
- závislost na presenteru není nic tfuj, je to architektura Nette – presenter je vždy nejvyšší rodič komponentové struktury
- vůbec ten tvůj poslední odstavec nechápu – v Quickstartu se žádná komponenta formuláře nepíše
Ad 1) To jsem se ne moc hezky vyjádřil. Jasně že je komponenta… to i samotný Control. Myslel jsem to tak, že tam není jak si udělat komponentu, která bude představovat formulář (extra třídu, obdobně jak je to ukázáno s děděním od třídy Control).
Ad 2) Toto se vztahuje k bodu 1.
Ad 3) Ok. Shrnu to. Díky metodě attached se nemusí předávat v konstruktoru, nic méně to není špatně, ale jestli se nepletu může to nějaký budoucí BC break změnit.
- https://doc.nette.org/cs/quickstart a metoda createComponentTaskForm vytvoří komponentu, která představuje vykreslitelný formulář (třída Nette\Application\UI\Form)
- Vojtěch Dobeš
- Gold Partner | 1316
Ad 1) Není to tam (Bohu díky), protože to rozhodně není nějaká best-practice nebo něco, co by měl člověk často dělat. Jsou hezčí způsoby.
Ad 3) Moje shrnutí: dředávání přes konstruktor je nyní v Nette pouze
z důvodu zpětné kompatibility. Tečka :). Metoda attached
je v Nette snad od prvopočátku. Pamatuji si na ni i ze školení.
I z pročítání dokumentace.