Informace o přihlášeném uživateli v Control – komponentě

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

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?

  1. DI – nevím jak ?
  2. předávat si id přihlášeného uživatele do konstruktoru ?
ZZromanZZ
Člen | 87
+
0
-

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)

motorcb
Člen | 552
+
0
-

ZZromanZZ:

Díky, ovšem to moc dobře nechápu.. K čemu je to proměnná $name?

ViPEr*CZ*
Člen | 817
+
0
-

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! Parent konstruktor má totiž takovýto tvar:

public function __construct(IContainer $parent = NULL, $name = NULL)
ViPEr*CZ*
Člen | 817
+
0
-

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
+
0
-

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
+
0
-

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žíš.

Majkl578
Moderator | 1364
+
0
-

není potřeba předávat rodiče, stačí ho zavolat

Ani to už není nutné. :)

ViPEr*CZ*
Člen | 817
+
0
-

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)

ZZromanZZ
Člen | 87
+
0
-

A co když usera potřebuješ již v konstuktoru nějaké komponenty? Tak jsem pochopil původní otázku.

Majkl578
Moderator | 1364
+
0
-

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
+
0
-

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

motorcb
Člen | 552
+
0
-

ZZromanZZ:

Přesně… Potřeboval bych usera už v konstruktoru… Jak na to?

ViPEr*CZ*
Člen | 817
+
0
-

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
+
0
-

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
+
0
-

**@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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

**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
+
0
-

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)

motorcb
Člen | 552
+
0
-

vojtech.dobes:

Díky. Přes attached by to bylo asi nejlepší. Jak přes atached dostanu informace o userovi?

Díky

Vojtěch Dobeš
Gold Partner | 1316
+
0
-

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 // ...
	}
}
Jan Mikeš
Člen | 771
+
0
-

Predpokladam, ze instanceof je tam pouze kvuli best practise, kdy se da ocekavat ze $parent neni Presenter? Komponenta v komponente? Nic jineho me nenapada.

Zeptam se primo – pokud casto zapominam a mam rad mene psani, muzu podminku s instanceof vynechat?

Vojtěch Dobeš
Gold Partner | 1316
+
0
-

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.

Jan Mikeš
Člen | 771
+
0
-

Abych se priznal, s nette jsem kamarad uz 2 roky a s attached() jsem se setkal az dnes, vse jsem vzdy resil v konstruktoru komponenty, je to tedy pro me take novinka, proto takova hloupa otazka :).

jasir
Člen | 746
+
0
-

Není nejlepší si závislosti do komponent injektovat rovnou konstruktorem?

protected function createCommonControl() {
   return new SomeControl($this->user, ...);
}
Jan Mikeš
Člen | 771
+
0
-

Zavislosti ano (jinak se do komponenty ani dostat nedaji, nebo snad JO? jeste settery..) ale jestli jsem spravne pochopil z toho co jsem tu procetl tak veskere dalsi operace a logiku smerovat do attached()?

Editoval Lexi (6. 3. 2013 21:36)

Vojtěch Dobeš
Gold Partner | 1316
+
0
-

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
+
0
-

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
+
0
-

ViPErCZ

  1. formulář je komponenta
  2. obvykle nevytváříme komponentu formuláře (v Nette už je hotová)
  3. závislost na presenteru není nic tfuj, je to architektura Nette – presenter je vždy nejvyšší rodič komponentové struktury
  4. vůbec ten tvůj poslední odstavec nechápu – v Quickstartu se žádná komponenta formuláře nepíše
ViPEr*CZ*
Člen | 817
+
0
-

vojtech.dobes napsal(a):

ViPErCZ

  1. formulář je komponenta
  2. obvykle nevytváříme komponentu formuláře (v Nette už je hotová)
  3. závislost na presenteru není nic tfuj, je to architektura Nette – presenter je vždy nejvyšší rodič komponentové struktury
  4. 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.

  1. 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
+
0
-

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.

ViPEr*CZ*
Člen | 817
+
0
-

Ad 1) Omrknu to, protože takhle to používám celkem dlouho a teď zjišťuji, že to není zrovna best-practice.

Děkuji za ujasnění.