Formuláře samostatně v souborech

Rndoom04
Člen | 72
+
0
-

Zdravíčko,
netušíte jak správně udělat jednotlivé komponenty formulářů zvlášť do souborů?

Totiž cílem má být to, že basePresenter má obsahovat třeba 20 různých formulářů – budou předpřipravené a klient si bude moci navolit, které chce kde zobrazovat. V basePresenteru to má být z důvodu, že formuláře se mohou na webu vyskytovat kdekoliv (na libovolné stránce). Zapisovat všechny možné formuláře do jednoho BasePresenter.php opravdu nechci, proto bych je rád osamostatnil např. do souborů a pak je něčím includnul. Ale nemám tušení, jak na to.

Děkuji za popostrčení. :)

MajklNajt
Člen | 471
+
-3
-

Skús Traity

Marek Bartoš
Nette Blogger | 1155
+
+1
-

I komponenty mohou mít komponenty. Takže si vytvoříš třídu komponenty a ta bude obsahovat komponentu s celým formulářem. Namísto formuláře tak vykresluješ jen tu obalující komponentu.

https://doc.nette.org/…n/components#…

Editoval Marek Bartoš (24. 7. 2022 16:05)

Marek Znojil
Člen | 76
+
-1
-

Ahoj, na tohle by se mohl hodit accessor:
https://doc.nette.org/…tion/factory#…

Marek Bartoš
Nette Blogger | 1155
+
0
-

Marek Znojil napsal(a):

Ahoj, na tohle by se mohl hodit accessor:
https://doc.nette.org/…tion/factory#…

Tím se řeší injectování závislostí a jejich lazy-loading, nikoli oddělení komponent do samostatných tříd/souborů. Je to krok navíc.

A když už, tak na komponenty se má používat factory, ne accesor (create() namísto get()) – jinak bys jednu komponentu nemohl na stránce vykreslit vícekrát.

MajklNajt
Člen | 471
+
0
-

Tí čo mi dali mínus, podľa mňa @Rndoom04 ovláda, že si má formulár vytvárať v továrni, ale rieši práve to, aby nemal 20× inject, 20× createComponentXxx…

Rndoom04
Člen | 72
+
0
-

Děkuji všem za odpovědi. Přesně jak se tu píše.

Aktuálně mám 20× v basePresenter.php createComponentNejakyNazevForm a celá tato komponenta zabírá třeba i 100 řádků. Protože je mnoho inputů a nějaké to následné zpracování. Takže je to aktuálně velmi nepřehledné. Tento způsob mi vyhovoval, dokud jsem měl jen pár formulářů, ale usnadnilo by mi to, když bych celou tu komponentu vzal, strčil do souboru, ty už jen naincludoval a měl něco jako:

// Formuláře typu aaa
require_once(APP_DIR."/Model/Formulare/aaa/form1.php");
require_once(APP_DIR."/Model/Formulare/aaa/form2.php");
require_once(APP_DIR."/Model/Formulare/aaa/form3.php");

// Formuláře typu bbb
require_once(APP_DIR."/Model/Formulare/bbb/form1.php");
require_once(APP_DIR."/Model/Formulare/bbb/form2.php");
require_once(APP_DIR."/Model/Formulare/bbb/form3.php");

Editoval Rndoom04 (25. 7. 2022 17:54)

Marek Bartoš
Nette Blogger | 1155
+
+1
-

require_once(APP_DIR.„/Model/Formulare/aaa/form1.php“);

Tohle nikdy dělat nebudeš, od načítání souborů je autoloading. V app/Bootstrap.php ve výchozím nastavení máš robotloader, který hledá třídy v app složce. Eventuelně je standard používat PSR-4 https://getcomposer.org/…04-schema.md#…


Teď děláš v presenteru něco takového

namespace Example\Presenter;

class ExamplePresenter extends \Nette\Application\UI\Presenter
{

	public function createComponentReportForm(): Form
	{
		$form = new \Nette\Application\UI\Form();
		// ...
		return $form;
	}

}

Kód formuláře vůbec nemusíš mít v presenteru, můžeš si vytvořit komponentu

namespace Example\Control;

class ReportControl extends \Nette\Application\UI\Control
{

	public function render(): void
	{
		$this->template->setFile(/* TODO - vytvoříš si latte soubor, vypíšeš v něm formulář a sem předáš cestu k souboru */);
		$this->template->render();
	}

	public function createComponentForm(): Form
	{
		$form = new \Nette\Application\UI\Form();
		// ...
		return $form;
	}

}

Pro komponentu si vytvoříš factory (ta slouží pro předávání závislostí, abys v presenteru nemusel psát new ExampleControl($this->dep1, $this->dep2, ...) a předávat závislosti přes něj)

namespace Example\Control;

interface ReportControlFactory {
	public function create(): \Example\Control\ReportControl;
}

Factory zaregistruješ v neonu a Nette ti pro ni vygeneruje třídu vytvářející ReportControl:

services:
	- Example\Control\ReportControlFactory

V presenteru nakonec vypíšeš jen komponentu z factory

namespace Example\Presenter;

class ExamplePresenter extends \Nette\Application\UI\Presenter
{

	/** @inject **/
	public \Example\Control\ReportControlFactory $reportControlFactory;

	public function createComponentReportForm(): \Example\Control\ReportControl
	{
		return $this->reportControlFactory->create();
	}

}

Tím se ti kód v presenteru zredukuje na volání create() metody a na získání služby z DI.

Editoval Marek Bartoš (25. 7. 2022 16:13)

Rndoom04
Člen | 72
+
0
-

Děkuji za odpověd. Mám pocit, že už jsem to někdy v minulosti takto řešil. Cílem jsem měl úplně zredukovat i tu public function createComponentReportForm(), ale co nadělám.

Nicméně zkoušel jsem vytvořit traitu i továrničku via (https://doc.nette.org/…in-presenter), ale hlásí mi to „Cannot declare class TestFormFactory, because the name is already in use“. Totiž ať si tam vymyslím jakýkoliv název, který jsem opravdu nikdy nepoužít nemohl, stále mi to hlásí. Netušíte někdo, v čem dělám chybu?

V common.neon to mám, use jsem také použil. Nerozumím tomu. :(

Marek Bartoš
Nette Blogger | 1155
+
0
-

Cannot declare class TestFormFactory, because the name is already in use

Nepoužíváš někde require nebo include? Ty soubory se vážně načítají samy, nemusíš je načítat sám.

Rndoom04
Člen | 72
+
0
-

Nepoužívám. Proto jsem v předchozím příspěvku psal „něco jako“. Nenapadlo by mě nic takového použít. :)

Editoval Rndoom04 (25. 7. 2022 18:08)

Petr Parolek
Člen | 455
+
-1
-

Rndoom04 napsal(a):

Děkuji za odpověd. Mám pocit, že už jsem to někdy v minulosti takto řešil. Cílem jsem měl úplně zredukovat i tu public function createComponentReportForm(), ale co nadělám.

Nicméně zkoušel jsem vytvořit traitu i továrničku via (https://doc.nette.org/…in-presenter), ale hlásí mi to „Cannot declare class TestFormFactory, because the name is already in use“. Totiž ať si tam vymyslím jakýkoliv název, který jsem opravdu nikdy nepoužít nemohl, stále mi to hlásí. Netušíte někdo, v čem dělám chybu?

V common.neon to mám, use jsem také použil. Nerozumím tomu. :(

Řešil jsem to a jde to viz https://github.com/…nets-sandbox

Marek Bartoš
Nette Blogger | 1155
+
0
-

Nejspíš nemáš duplicitu, ale nějaký autoloader se snaží stejnou třídu načítat 2×.

Nastavoval jsi si kromě robot loaderu v Bootstrap i Composer nebo nějaký jiný autoloader? Jak je máš nastavené?
Tahle chyba se dá spolehlivě izolovat tak, že vyřadíš všechny autoloadery, v Composer json si složku s appkou namapuješ přes classmap a zavoláš composer dump.

Sice pak bez manuální obnovy autoloaderu nefunguje přidávání nových tříd, ale aspoň budeš mít jistotu že je to ono. Pak můžeš řešit třeba jak přes PSR-4 načítat všechny soubory

Seznam autoloaderů zjistíš tak, že před vrácením Configurator v Bootstrap vypíšeš bdump(spl_autoload_functions());


To co posílá Petr spočívá v přetížení metody createComponent(), abys mohl to kde se hledají komponent řešit sám a ne přes createComponentExample(). Bez znalosti tvého usecase těžko říct, zda je to pro tebe použitelné a může to být dost omezující. Nemá cenu řešit, dokud nemáš hotové alespoň oddělení komponent a factories pro ně

Editoval Marek Bartoš (25. 7. 2022 18:39)

Pepino
Člen | 247
+
0
-

Co se týče minimalizace kódu tak bych jen chtěl přidat ještě 2 poznatky.

  1. Každou továrničku není potřeba registrovat zvlášť. Existuje přece https://doc.nette.org/…onfiguration#…
  2. Vytváření komponenty v presenteru taky nevyžaduje psát createComponentXXX, stačí např. v action metodě napsat $this['mujFormular'] = $this->mujFormularFactory->create();

PS: Nepíšu nic o přehlednosti, ale jen o minimalizaci kódu.

Editoval Pepino (26. 7. 2022 8:21)