Vykreslení formuláře v jiném presenteru

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

Tvořím redakční systém, kde mám různé „moduly“ (fotogalegie, články…) a chci k nim mít možnost vkládat komentáře.

Vytvořil jsem si nový modul „komentáře“, který includuji do @layout.phtml. Problém nastává, když v komentářích (např. Komentare.vypis.phtml) použiju továrničku na formulář, něco jako {control pridat}. Logicky to nefunguje, neboť to hledá v aktuálním presenteru (třeba fotogalerie).

Můj dotaz tedy zní… Je možné nějak vkládát továrničku z jiného presenteru? Něco jako {control Fotogalerie:pridat}.

Děkuji.

nanuqcz
Člen | 822
+
0
-

Ahoj, tohle se řeší tak, že továrničku na komponentu si dáš do BasePresenteru a od něj pak dědí ostatní presentery (myslím že i přímo v Sandboxu to tak je). Díky tomu budeš mít přístup ke komponentě ve všech presenterech a šablonach, které od BasePresenteru dědí.

zener
Člen | 17
+
0
-

xxxObiWan: Díky za reakci, taky mě tento způsob napadl. Chtěl jsem mít jednotlivé moduly co nejméně závislé na ostatních, proto jsem hledal jiné řešení.

nanuqcz
Člen | 822
+
0
-

V tom případě by měl mít každý modul svůj BasePresenter a dal bych to do něho. Tohle je v Nette standardní řešení ;-)

zener
Člen | 17
+
0
-

Ok, udělám to tak.

Ještě jednou díky za rady.

petr.pavel
Člen | 535
+
0
-

Rád bych tohle téma znovu otevřel.

Chápu, proč někdo doporučuje definovat formulář i obslužné funkce v předkovi, a pro některé situace to může být čisté řešení. Když ale budu mít vyhledávací formuláře zákazníků, dodavatelů, materiálu… na jednotlivých stránkách těchto entit, ale současně je budu chtít ještě zopakovat na stránce hlavního velínu, tak by se mi logika vyhledávání v jednotlivých entitách slila ve společném předku. To přece není správné. Jasně, že skutečné vyhledávání bude v modelu, ale i tak.

Asi by šlo definovat pro každý z formulářů samostatnou komponentu, ale to je jako jít na mravence s kanónem. Jestli mi někdo předložíte celé řešení, které nezabírá dvě stránky, tak jsem ochoten připustit opak.

Úplně nejlepší by mi přišlo mít definovaný formulář v presenteru entity a z velínu ho jen nějak použít. Zenerovo vysněné {control Fotogalerie:pridat} by bylo super, ale není implementované.
Jinak to sice jde, ale je to prasárna.

Nejbližší lepší postup podle mě je definovat formuláře na úplně jiném místě, ale to pak stejně musíte řešit, kde se budou zpracovávat po odeslání.

Teoreticky by šlo formulář zachycovat v presenteru velínu a přesměrovávat hodnoty jinam, ale to je extra krok navíc.

Osobně se mi zatím nejvíc líbí formulář rovnou odesílat do presenteru/akce, která ho má zpracovat. Probírá se to tady, ale téma pak uklouzlo jinam. Takže bych to rád nějak shrnul a jestli nebudete nikdo proti, připsal bych to i do dokumentace.

Formulář definujte podle příkladu v dokumentaci, ale v továrničce pak místo přidání callbacku do $form->onSuccess zavolejte následující setAction(). Odesílá do presenteru Search, akce default.

$url = $this->link('Search:default', array('do' => $name.self::NAME_SEPARATOR.'submit'));
$form->setAction($url);

Nette Framework 2.0-beta (revision f38d86f released on 2011–08–24)

Editoval petr.pavel (29. 8. 2011 10:43)

22
Člen | 1478
+
0
-

asi bych si udělal vlastní komponentu, která bude obecně umět sestavit vyhledavácí formulář a pak si jen podle potřeby zavolám buď komponentu, pokud rozšiřuji stávajíci vyhledávací form nebo udělám novou komponentu, pokud je form úplně jiný:

public function createComponentSearch()
{
	$search = new Search();
	$search->add('city', 'Město');

	return $search;
}

//rozšíření
public function createComponentSearchMore()
{
	$search = $this->getComponent('search');
	$search->add('district', 'Kraj');
	return $search;
}

no a vždycky mi to vyhledá položky v DB, co vypadnou z formu a do modelu pošlu jen proměnnou $filter

Editoval 22 (29. 8. 2011 11:02)

petr.pavel
Člen | 535
+
0
-

@22: Můžeš, prosím, doplnit kód, kterým bys zachytával odeslaný formulář? Nebo jestli je někde k dispozici kompletní řešení, mohl bys poslat odkaz?

22
Člen | 1478
+
0
-

… co znamená zachytávat odeslaný formulář?? Myslíš, jak by vypdala ta komponenta??

petr.pavel
Člen | 535
+
0
-

Asi používám blbou terminologii. Při nejjednodušší implementaci formuláře v Nette se vyrobí v createComponentMujFormular() a pomocí třeba $form->onSuccess[] = callback($this, ‚mujFormularOdeslan‘); se pak zpracuje v tom samém presenteru v metodě mujFormularOdeslan(). Tomu říkám zachytit odeslaný formulář – odeslané hodnoty zpracuje mujFormularOdeslan().

Nevím, kde a jak by se v případě komponenty tohle odehrálo a jak by to celé vypadalo. Bavíme se v kontextu tohoto vlákna, ne obecně.

22
Člen | 1478
+
0
-

to záleží na tobě, buď může být callback přímo v komponentně nebo si můžeš navěsit callback až v presenteru.

petr.pavel
Člen | 535
+
0
-

Přeci jen bych někoho poprosil o kompletní kód:

  1. úplnou definici komponenty, do formuláře stačí jediná položka + tlačítko
  2. různé vykreslení ve dvou šablonách; třeba vynechat některé položky, vykreslit vedle sebe, místo v tabulce…
  3. použití ve dvou presenterech
  4. zpracování odeslaných hodnot formuláře pouze na jednom místě, tedy asi v komponentě; stačí obdoba dump($form->getValues());

A ještě otázka: jestli tomu dobře rozumím, kompomentu vždycky musím renderovat sám. Nemůžu tedy ji vykreslit v šabloně presenteru/akce pomocí makra {form …}. Jestli je to tak, tak bych mohl bod (2) splnit pouze tak, že bych definoval víc renderovacích metod a volal je ze šablony přes {control mujFormular:nazevVzhledu}.

Patrik Votoček
Člen | 2221
+
0
-

tak ještě jendou a lépe:

class MySuperForm extends \Nette\Application\UI\Form
{
	/** @var mixed */
	private $modelService;
	/** @var \Nette\Application\UI\Link */
	private $successLink;

	public function __construct($modelService)
	{
		parent::__construct();
		$this->modelService = $modelService;

		$this->setup();
	}

	protected fucntion setup()
	{
		$this->addTextArea('text', "Text");

		$this->addSubmit('sub', "Save");

		$this->onSuccess[] = callback($this, 'process');
	}

	public function process()
	{
		try {
			$this->modelService->create($form->values);
		} catch (ModelException $e) {
			foreach ($e->errors as $name => $messages) {
				foreach ($messages as $message) {
					$this[$name]->addError($message);
				}
			}
		}
	}
}

class ArticlePresenter extends BasePresenter
{
	protected function createComponentMyForm()
	{
		return new MyForm($this->context->articleModelService);
	}
}

class GalleryPresenter extends BasePresenter
{
	protected function createComponentMyForm()
	{
		$form = new MySuperForm($this->context->galleryModelService);
		$form->addMultileFile('images', "Images");
		return $form;
	}
}
{* Gallery/default.latte *}
{control myForm}
{* Article/default.latte *}
{form myForm}
{label text /}{input text}
{input sub}
{/form}
petr.pavel
Člen | 535
+
0
-

Super, díky Patriku! Netušil jsem, že i v případě formuláře (potomka AppForm) můžu zpracovávat jeho odeslání přímo v jeho třídě.

Upřímně, stránka o komponentách má dost velké mezery. Nevyplynulo mi z ní, že by se potomek AppForm taky nazýval komponenta, v příkladech se dědí jen z Control. Jasně že se tam každou chvíli mluví o formulářích, ale myslel jsem, že to jsou formuláře definované uvnitř nějakého většího celku, který se jmenuje komponenta.

Navíc tvrzení, že se o vykreslení musíme postarat sami v metodě render. Jak to teď chápu, tak můžeme, ale nemusíme.

Pořád ještě nejsem v tomhle dost silný v kramflecích, takže si zdaleka netroufám dokumentaci komponent upravovat sám. Určitě by to ale chtělo. Komponenty do hloubky bych určitě vyčlenil do zvláštní stránky. Je to na mě strašně složité, budu rád, když někdy pochopím tu první část a stránka je už takhle moc dlouhá.

Ještě si ten tvůj kód vyzkouším a doplním pak něco k formulářům v presenteru.

P.S. Tady na fóru nefunguje odkaz do dokumentace dle Jak zapisovat kód v tomto fóru. Myslím tím [[doc:debugging]] i [[Laděnky | doc:debugging]]. Mohl by to někdo opravit, prosím?

22
Člen | 1478
+
0
-

Komponenty jsou všechno, co má něco společného s https://api.nette.org/…mponent.html
Presenter je taky komponenta a každý Control je taky komponenta…

petr.pavel
Člen | 535
+
0
-

Ještě otázka k Patrikově kódu, nešlo by se nějak obejít bez createComponent…() v presenterech, které ten můj formulář používají v šabloně?

Ve tvém příkladu se ještě doplňují kolonky a předává model, takže createComponent…() potřebuji. Díky, že's to do příkladu uvedl. Kdyby mi ale stačil přesně ten stejný formulář (strukturou) a stejné zpracování, šlo by se nějak obejít bez createComponent…()? Rád bych i nadále vykresloval pomocí makra {form …}

22
Člen | 1478
+
0
-

nejde to bez createComponent<name> a můžeš přece vykreslovat s makrem {form} viz. 2.příklad (GalleryPresenter).

Editoval 22 (31. 8. 2011 10:56)

Patrik Votoček
Člen | 2221
+
0
-

petr.pavel napsal(a):

Navíc tvrzení, že se o vykreslení musíme postarat sami v metodě render. Jak to teď chápu, tak můžeme, ale nemusíme.

U klasických komponent musíme. Ber to tak že Nette\Application\UI\Form je chytřejší base komponenta pro tvorbu formulářů, kterou můžeš rovnou instancovat.

… Určitě by to ale chtělo. Komponenty do hloubky bych určitě vyčlenil do zvláštní stránky.

Tohle je už moc „hluboké“ takovéhle specifické věci patří do wiki resp. Kuchařky.

P.S. Tady na fóru nefunguje odkaz do dokumentace dle Jak zapisovat kód v tomto fóru. Myslím tím [[doc:debugging]] i [[Laděnky | doc:debugging]]. Mohl by to někdo opravit, prosím?

Co ti na tom nefunguje? mě to funguje.

Ještě otázka k Patrikově kódu, nešlo by se nějak obejít bez createComponent…() v presenterech, které ten můj formulář používají v šabloně?

Můžeš si přetížit Nette\ComponentModel\Container::createComponent() a zautomatizovat to. Nebo si hodit příslušnou továrničku do BasePresenteru.

petr.pavel
Člen | 535
+
0
-

Nefunkční odkazy do dokumentace:
Když zkopíruji příklad z návodu
získám něco jiného, než co uvádí návod:

A teď si najeď myší na ty odkazy. Není to platná adresa, ale „doc:cs:debugging“.

Přetížení createComponent(): Jo! To je výborný nápad, díky.

Filip Procházka
Moderator | 4668
+
0
-

Přetížení createComponent může být cestou do pekel, pokud s tím komponenty nepočítají.