Termíny, výrazy, trošku lidsky
- Klobás
- Člen | 113
Ahoj,
nějakou dobu v Nette dělám, rozumím životnímu cyklu, DI, databázi,
ajaxu.
Několik menších projektů jsem v tom napsal, ale ztrácím se v zavedených
názvosloví, byl by někdo ochoten mi to napsat jak pro prvnáčka?
Např. zde: https://doc.nette.org/…s/form-reuse
Nerozumím vůbec pojmům továrna / generovaná továrna a co já vím co se
ještě používá.
Rozdíl mezi tímto dvojím použitím vidím v tomto:
- Továrna na UI\Form
Vytvoří se obyčejná třída, která se připojí jako služba ( asi i kvůli autowiringu?) a pak s ní můžu pracovat kdekoliv v jakémkoliv presenteru.
- Generovaná továrnička
Rozdíl oproti 1) je ten, že to je controlka, a píše se, že je to vhodné pokud chceme použít (nese) vlastní šablonu.
To je skutečně jediný rozdíl? V 1čce to nejde? Pokud bych tedy 2ku použil v šabloně presenteru, tak šablona komponenty bude umístěná , resp nastavená v CategoryForm:renderDefault?
1čka to neumí a tudíž bych se musel spokojit s defaultním rendererem nebo si ji vypsat ručně?
Díky za objasnění
Možná kdyby mi někdo ukázal na velmi jednoduchém příkladu použítí obou způsobů, tak bych tomu spíše porozuměl.
A také nevím, proč některé (jakékoliv) věci připojovat jako služby (u Modelu kvůli Autowiringu je to jasné), ale proč se někdy připojují celé Presentery/Controlky …
V tomhle fakt plavu.
Editoval Klobás (25. 1. 2018 10:05)
- Šaman
- Člen | 2666
Rozdíl je v tomhle:
(Továrna na) UI\Form vs. Formulář
v UI\Control (a generovaná továrnička)
Poprvé pracuješ s instancí Form, podruhé s komponentou. A jen tak mimochodem, komponenta se dá registrovat pomocí automaticky vygenerované tovární třídy (takže si napíšeš jen rozhraní, ale nepíšeš samotnou třídu, protože je to pořád stejná rutina). Klidně si ale můžeš napsat tu továrnu sám, je to obyčejná služba, která vrací novou instanci té komponenty.
Dodatek: Ano, komponenta obaluje nějakou logiku a navíc šablonu. Samotný formulář šablonu neobsahuje. Buď se použije renderer (třída schopná vykreslit formulář stále stejným způsobem), nebo ho musíš v šabloně presenteru (nebo komponenty) vykreslit ručně.
Při použití komponenty raději vůbec nepoužívej pohledy
(CategoryFormControl:default
), doporučuji rozlišovat už
v názvu, jestli je objekt komponenta, nebo formulář
(CategoryFormControl
vs. CategoryForm
) a i kdybys
pohledy komponent opravdu používat chtěl (a věděl že s nimi jsou
problémy ve snippetech), tak se nepíše
CategoryFormControl:renderDefault
, ale jen
CategoryFormControl:default
. Běžně ale v komponentách
používáš jen metodu render()
a vykresluješ pomocí
{control CategoryFormControl}
.
Editoval Šaman (25. 1. 2018 10:21)
- CZechBoY
- Člen | 3608
Tovarna je implementace Factory patternu a dela to programator sam –
nevyuziva prakticky zsdnou vyhodu frameworku (snad krom di).
Generovana tovarna je generovana frameworkem a jeji zapis se dela pres
interface.
priklad generovane tovarny:
interface IGenerovanaTovarna
{
/** @return NejakaTrida */
public function create();
}
tuto generovanou tovarnu (ten interface) potom registrujes jako sluzbu a
klasicky typehintujes tento interface.
Nette vygeneruje klasickou tridu za tebe a implementuje dany interface. Je
potreba uvest co ma dana create metoda vracet – bud phpdoc nebo return typ
(od php 7).
Doplním, že výsledkem generované továrny je klasická továrna – rozdíl
je tedy jen ten, že tu třídu za tebe vygeneruje Nette podle
nějaké konvence.
Editoval CZechBoY (25. 1. 2018 10:21)
- Šaman
- Člen | 2666
Jinak za sebe doporučuji používat čisté formuláře (tedy neobalovat je komponentou). S komponentou bývají problémy, viz třeba toto. Není to chyba komponenty, ale toho, že člověk zapomene, že presenter pracuje s komponentou a nikoliv s formulářem, který je až v té komponentě. Složitěji se pak z presenteru nastavují redirecty a podobně.
Komponenta je dobrá právě tehdy, pokud potřebuješ mít k formuláři i jeho šablonu. A pokud ten formulář budeš chtít na více místech.
- Pokud chceš obyčejný formulář, pak ti stačí Form a renderer (defaultní, nebo třeba upravený pro CSS Bootstrap).
- Pokud chceš unikátní formulář, pak si většinou vystačíš s Formem a manuálním vykreslením v šabloně.
- Ale pokud chceš unikátní formulář na více místech, dává smysl komponenta. Vykresluješ tedy taky manuálně, ale v šabloně té komponenty a v pak do presenteru jen vložíš komponentu. Změna komponenty se projeví na všech místech… Ale nese to určité riziko chyb, když zapomeneš, že presenter pracuje s komponentou a chceš s ní pracovat jako s formulářem. I proto je dobré vždy mít název, ze kterého je to poznat.
Editoval Šaman (25. 1. 2018 11:01)
- Klobás
- Člen | 113
Ano, takto to právě dělám, bud formulář vykreslím automaticky (standardní renderer, nebo mám BTS renderer, nebo vlastní rendered) a v případě fakt složitého formuláře jej vykresluji ručně, políčko po políčku.
Tyhle ty 3 body co jsi popsal, dávají smysl, moc díky.
Já v nette pracuji nebo se snažím pracovat něco přes rok, a samozřejmě člověk dělá u toho i jiné věci (nejenom PHP, ale např. něco s DB, něco kóduje, řeší občas klienty / marketink, tj několik pozic v 1) a občas se pak diví, co tu velezkušení na Planette nebo v návodech popisují, proto z toho mám občas depresi :-) a i něco zapomínám a zase se zpětně k něčemu vracím.
Snad nejsem sám kdo to tak má :)
Editoval Klobás (25. 1. 2018 11:09)
- Klobás
- Člen | 113
Můžeme se k tomu na chvíli vrátit, přemýšlel jsem nad tím, četl jsem nějaké články a vyšla mi z toho nejlépe generovaná továrnička.
Ted mi jde jen o to, jestli jsem pochopil vše a nedělám něco špatně.
Takto vypadá tedy komponenta, není tam nic objevného, součastí jen pro testování je i interface.
Je to samozřejmě připojené v neonu
- App\FrontModule\Components\IContactFormFactory
A ted jestli to chápu dobře
V presenteru si vytvořím továrnu, ten validační a success handler na odeslání tam mam jen tak na test.
<?php
/** @var App\FrontModule\Components\IContactFormFactory @inject */
public $contactFormFactory;
.
.
.
protected function createComponentContactForm()
{
$control = $this->contactFormFactory->create();
$control['createForm']->onValidate[] = array($this, 'validateForm');
$control['createForm']->onSuccess[] = $this->contactFormFormSubmitted;
return $control;
}
?>
A nyní mám tyto možnosti jak to vykreslit, vykreslujeme v presenteru (máme akci Presenter:default) takže default.latte
- Vytvoří mi se mi automaticky formulář díky nativnímu form rendereru
<?php
{control contactForm-createForm} // musíme to volat takhle, protože se jedná o komponentu v komponente.
?>
- Mám možnost si renderer ovlivnit, třeba takto
<?php
protected function createComponentContactForm()
{
$control = $this->contactFormFactory->create();
$renderer = $control['createForm']->getRenderer();
$renderer->wrappers['controls']['container'] = 'dl';
$renderer->wrappers['pair']['container'] = NULL;
$renderer->wrappers['label']['container'] = 'dt';
$renderer->wrappers['control']['container'] = 'dd';
}
?>
- Kdybych se rozhodl, že bych potřeboval formulář vyrenderovat přes
komponentu a její vlastní render metodu tak změním volání kontrolky na
{control contactForm}
a samozřejmě musím mít v komponentně mít tedy render metodu a šablonu a tam si ručně vykreslím formulář. - Kdybych potřeboval různě vykreslovat formulář tak mne napadá, že bych si do kontrolky pouštěl nějakou proměnnou nebo přes nějaký setter bych si nastavil typ rendereru , nějak takto
<?php
protected function createComponentContactForm()
{
$control = $this->contactFormFactory->create();
$control->setMyRenderer('whatever..'); // a pak bych si nějakou vlastní logikou v komponetně zařidí jakou šablonu renderer vykreslí nebo tak ..., to už je fuk)
}
?>
Je to takto v pořádku, chápu to správně? Není něco z toho krkolomné? Díky moc.
Editoval Klobás (31. 1. 2018 20:36)
- Šaman
- Člen | 2666
Jak jsem psal – formuláře používám samostatně, bez obalení
komponentou. K vykreslení používám upravený BS3Renderer.
Takže mám vlastní tovární třídu (ne přes rozhraní, prostě třídu,
která umí vytvořit formulář), tu si injectnu do presenteru (komponenty) a
v metodě createComponentFooForm()
ten formulář pomocí továrny
vytvořím, nastavím redirecty a flashmessage a v šabloně ho už jen
vykreslím pomocí {control fooForm}
.
Komponenta to zbytečně zesložiťuje. Pokud ji nepotřebuješ (třeba kvůli nějaké práci se snippety, nebo ručnímu renderování na více místech), tak je to zbytečný overkill.
Mimochodem tu továrnu na formulář mám v rámci modelu. Je hned
u entity, na kterou se formulář váže. Protože pokud se změní struktura
entit, často se změní i formuláře. Zatímco presenteru už je to jedno,
ten prostě vezme formulář (který už obsahuje rutinu pro uložení dat),
přidá nějaké prezenční věci (kam se má udělat redirect, nebo vypsat
zprávu) a víc o něm vědět nepotřebuje. Je to trochu kontroverzní téma,
ale za mě to patří do modelu. (Tím myslím jeden model, celé M z MVP.
Nikoliv nějaký PersonModel
, což je konkrétní třída a navíc
nevhodně pojmenovaná.)
Editoval Šaman (31. 1. 2018 20:50)
- Klobás
- Člen | 113
@Šaman, díky za reakci. Já jsem to pochopil, pročítal jsem si
totiž nějaké tvoje starší příspěvky, konrétně ten kde jsi již tohle
popsal a David Matějka Ti tam kontruje, že používá generované továrničky
UI\Form. Proto jsem to tak zkusil.
Tvoje použití chápu taky, rozhodně jsem na tom líp, než před založením
diskuse.
Mohu tedy k 1) je to už takový způsob vykreslení, ke kterému moc
docházet nebude, ale zajímalo by mne, jestli bych to mohl vykreslit jinak než
přes kontrolka-subkontrolka, zkoušel jsem v továrně presenteru nevracet
celou KONTROLKU ale rovnou onen formulář, ale to
nešlo return $control['createForm'];
- CZechBoY
- Člen | 3608
Pripadne muzes u te varianty formular v komponente vyuzit metody render a jen v te metode nechat vyrenderovat formular. Vyhoda je ta, ze kdyz nekdy budes chtit renderovat rucne nebo obalit form do komponenty tak to zmenis jen na jednom miste.
public function render()
{
echo $this['form'];
}
- Klobás
- Člen | 113
Mno tohle je to samé ne? Zakomentovaná část viz tvoje použití
<?php
public function render()
{
// $this->template->setFile(__DIR__ . '/contact-form.latte');
// $this->template->render();
echo $this['createForm'];
}
?>
>>nebo obalit form do komponenty
Tomuhle nerozumím, jak tom myslíš?
PS. Pořád k té 1) je to v pořádku zápis?