Jak na předání stringu do layoutu

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

Ahoj,
řeším jeden problémek a hledal jsem po fóru a řešení jsem nenalezl.

Rád bych z komponenty, kterou volám z presenteru vypsal proměnnou do layoutu.

Presenter v render metodě:

$inzeraty = $this['inzeraty'];
$inzeraty->view = "viewCategory";

Šablona presenteru

{widget inzeraty}

V komponentě se klasicky volá render, který předává proměnné do šablony komponenty. Šablona komponenty se vykreslí do šablony presenteru.
Jde o vypsání názvu inzerátu do titulku webu „Název webu | název inzerátu“. Sice mám hotové řešení, ale to je takové všelijaké a není to ono. Nyní jsem ve fázi, kdy si dělám refaktoring projektu a chci docílit kloudného výsledku, bez nějakých hacků :-)
Do šablony komponenty samozřejmě předávám název inzerátu, takže jsem zkoušel i dědění šalon:

v layoutu

Název webu | {block #title}{/block}

v šabloně komponenty

{block #title}Název inzerátu{/block}

ale nefachá, pravděpodobně posloupností vykreslování. V komponentě jsem zkoušel i proměnnou „public $title“ uvést jako persistentí a v presenteru jí získat – taky jsem neuspěl a opět pravděpodobně způsobem vykreslování…

Máte někdo lepší zkušenosti?

Tharos
Člen | 1030
+
0
-

V téhle věci je v Nette jeden logický zádrhel: „líně“ vytvořená komponenta se vytváří, připojuje a vykresluje až v době, kdy už je layout pohledu vykreslen. Z komponenty lze přes $this->getPresenter()->template->... do layoutu proměnnou nastavit, zrovna tak je možné provést i další akce v presenteru, ale je nutné tak učinit včas.

Momentálně se to dá řešit myslím jen „nelínou“ inicializací komponenty (například v action metodě, jako se to v Nette dělalo kdysi dávno ještě před existencí továrniček).

Na stejný problém bys narazil například v momentě, kdy bys chtěl z komponenty, která se vykresluje někam do těla stránky, připojit do záhlaví řekněme vazbu na nějaký JavaScriptový či CSS soubor (který může být například specifický pro danou komponentu). Tenhle problém se tu na fóru čas od času řeší (kdyžtak zapátrej) a mám pocit, že zatím nikdo nepřišel s žádným ultimátním řešením.

Editoval Tharos (17. 1. 2011 21:01)

Filip Procházka
Moderator | 4668
+
0
-

Ultimátní je definovat si titulek stránky v render. Pokud šablona ví že v ní bude ta a ta komponenta, nevidím důvod proč by to nemohlo být definované už v presenteru.

Něco jako inzeráty se podle mě nehodí na komponentu, pokud je to komponenta, pravděpodobně nebude hlavním obsahem zobrazené stránky a neměla by proto moc ovlivňovat titulek a h1.

Tharos
Člen | 1030
+
0
-

HosipLan napsal(a):

pokud je to komponenta, pravděpodobně nebude hlavním obsahem zobrazené stránky a neměla by proto moc ovlivňovat titulek a h1

Téhle drobnosti si dovolím oponovat. :) Nevidím důvod, proč by tak tomu nemohlo být. V mém skromném CMSku, které implementuje populární přiřazování modulů do předdefinovaných bloků, je skoro všechno na stránce komponentou. Hlavní obsah není nic jiného, než komponenta ({control mainContent}), ke které je pro konkrétní stránku namapován modul (modul pro jednoduchý HTML obsah).

V takovéto koncepci se s potřebou ovlivnit například titulek stránky či připojené JavaScripty setkávám dnes a denně a rozhodně si nemyslím, že se jedná o špatný návrh. Z komponent ovlivňuji presentery přes attached() a jen je zapotřebí připojit komponentu včas (já to dělám v action).

Edit: Abych byl přesnější, „skoro všechno“ u mě znamená opravdu prakticky všechno. :) Například i titulek webu řeším u sebe komponentou. To totiž výrazně usnadňuje inline editaci z frontendu. Pokud není přihlášen oprávněný správce, vykreslí se normálně titulek, zatímco správce vidí nejen titulek, ale i ikonky pro jeho okamžitou instantní úpravu či přechod do relevantní části backendu. Vyřešeno komponentou je to technicky triviální. Osobně jsem v Nette dospěl asi až k fanatické „komponentnosti“. :) Přijde mi, že řešit věci hojně přes komponenty přináší obrovské benefity (plus to zlepšuje přehlednost kód).

Editoval Tharos (18. 1. 2011 9:05)

Filip Procházka
Moderator | 4668
+
0
-

Z větší části souhlasím, ale přece jenom, co takhle mít v obsahu místo mainContent další presenter? Koneckonců, je to taky komponenta a pokud ho obalíš, tak aby ti pouze vykreslil sebe, bez odesílání obsahu, tak je to ještě lepší.

Mělo by za tímhle účelem stačit upravit metodu render a můžeš s tím pracovat jako s komponentou :)

Tak to mám namyšlené já, jeden GodPresenter, který se bude chovat jako vrstva nad všemi presentery, bude se starat o šablonu a bude předávat requesty jednotlivým presenterům, na základě požadavků pro vykreslení na aktuální stránce :) Takže důležitý obsah ⇒ presentery, méně důležitý obsah ⇒ komponenty.

Tharos
Člen | 1030
+
0
-

Noo, to by asi taky šlo, ALE :). Mně osobně tohle přijde jako už (zbytečná) komplikace, neřeknu-li přímo ohýbání frameworku. Jde zkrátka o používání jeho součástí trochu jinak, než je zamýšleno.

Požadavek na aplikaci se překládá na PresenterRequest. Vytvoří se instance patřičného presenteru a spustí se jeho životní cyklus. A tak dále a tak dále, nebudu tu opakovat první hodinu předmětu Nettevěda z druhého stupně ZŠ… :) Ve standardním životním cyklu aplikace se nepočítá s proběhnutím životního cyklu více presenterů, s výjimkou forwardů (používáte to někdo?). První potenciální problém: standardní generování odkazů. Zajímá nás kombinace presenteru a akce. Co kdyby někdo vytvářel odkaz na ty „vnitřní“ presentery?

Komponenty se daní snadno doplnit o pohledy i jistý životní cyklus, to dobře víš :). Pak už osobně nemám, co by mi u nich chybělo.

Osobně se dost bráním používání frameworku nestandardním způsobem. Vysvětlím proč: oni pak na mě všichni spoluvývojáři strašně nechápavě koukají. :) První verze mého CMSka podobným ohýbáním přetékala a nedělalo to dobrotu v tom smyslu, že když pak někdo jiný musel na nějakém webu v době mé nepřítomnosti dělat úpravy, nestíhal jsem na dovče zvedat telefony :). V dalších verzích jdu spíš cestou co největší integrace do Nette a jeho standardního používání. Tak, aby se kdokoliv, kdo s Nette umí, v systému dokázal velmi rychle zorientovat. A právě podobné použití presenterů by bylo proti této mojí filosofii. :)

Filip Procházka
Moderator | 4668
+
0
-

Pokud stanovíš že tyhle presentery jsou komponenty a mají namespace, přes který se k nim nedostane loader nevytvoříš k nim cestu.

Jde mi o to, že bych chtěl, aby mi router přeložil, na základě masky, adresu na parametry, předal request „hlavnímu“ presenteru a ten rozhodne co se dá udělá na základě komponent, které má vykreslit, podle oprávnění a seznamu komponent pro danou stránku.

Ostatně, takhle to udělám tak jako tak, ale ještě popřemýšlím, nerozšířit-li jenom životní cyklus Control ještě o pár dalších metod, abych nemusel zapojovat presentery, přecejenom to asi bude čistší. Dneska jsem nějaký hloupý, budu nad tím doma meditovat :P

srigi
Nette Blogger | 558
+
0
-

HosipLan napsal(a):

Tak to mám namyšlené já, jeden GodPresenter, který se bude chovat jako vrstva nad všemi presentery, bude se starat o šablonu a bude předávat requesty jednotlivým presenterům, na základě požadavků pro vykreslení na aktuální stránce :) Takže důležitý obsah ⇒ presentery, méně důležitý obsah ⇒ komponenty.

Mas to uz niekde rozpisanie, toto by ma zaujimalo (spustit viac Presenterov pocas RQ).

Filip Procházka
Moderator | 4668
+
0
-

Nemám a přemýšlím, že to ani dělat nebudu, ale šlo by to takhle ±

final class GodPresenter extends Nette\Application\Presenter
{

	public function run(PresenterRequest $request)
	{
		try {
			$this->request = $request;
			$this->payload = (object) NULL;
			$this->setParent($this->getParent(), $request->getPresenterName());

			// TODO: reimplementovat (kvůli private)
			$this->initGlobalParams();

			if ($this->autoCanonicalize) {
				$this->canonicalize();
			}
			if ($this->getHttpRequest()->isMethod('head')) {
				$this->terminate();
			}

			// příjem signálů
			$this['containers'] = $containers = $this->pageModel->queryRequest($request);

			$this->processSignal();

			foreach ($containers as $container) {
				if ($container instanceof PresenterContainer) {
					foreach ($container as $presenter) {
						$partialRequest = $container->createPartialPresenterRequest($request);
						$partialResponse = $presenter->run($partialRequest);
						if (!($partialResponse instanceof RenderResponse)) {
							return $this->response = $partialResponse;
						}

						// při renderování by PresenterContainer vracel pouze response
						// kontroloval by jestli presenter response obsahuje a pak by vrátil response jinak presenter
					}
				}
			}

			$this->sendTemplate();
		} catch (AbortException $e) {
			// continue with shutting down
		} /* finally */ {

			// asi zkopírovat z rodiče

			return $this->response;
		}
	}

}

Když jsem se s tím teď tak narychlo pral, tak jsem si začal uvědomovat spousty věcí co se musí ošetřit. Že z miliónu míst může přijít třeba signál pro přesměrování atp. Zkrátka ty presentery asi nebudou tak libový jak mi to připadalo dřív. Asi to bude opravdu chtít ty komponenty dědit od Nette\Application\Control a né Nette\Application\Presenter