Jak mít formulář včetně zpracování v samostatném souboru?
- Myiyk
- Člen | 321
Ahoj,
používal jsem přístup přes context, tak jsem si řekl, že to změním.
Problém je ovšem s formuláři.
Mám formulář kde se přidává/aktualizuje kategorie. Tento formulář mám v samostané třídě:
class CategoryForm extends Nette\Application\UI\Form
ale je problém se zpracováním formuláře, to zpracování bych chtěl provádět v rámci jedné třídy s formulářem. Jak se ale dostat k modelu? Přes context nechci, přes presenter ($this->presenter) to je (aspoň si to myslím) také nevhodné, protože v presenteru musím mít inject modelu jen kvůli tomu formuláři.
Jsem z toho zmaten a nevím kam se hnout.
Máte někdo řešení, které by umožňovalo změnu mezi přidáváním a
upravováním a zároveň, aby to bylo nějak elegantně napsáno?
Jestli máte nějaké nápady, tak sem s nimi. Díky
--edit--
Již při vytváření formuláře je potřeba databáze, protože používám multilang. Kolik jazyků, tolik názvů kategorie. Takže i kdybych ten form zpracovával v presenteru, tak bych buď v presenteru musel přidávat pole nebo nějak se dostat ve té třídě k modelu.
Editoval Myiyk (30. 8. 2013 23:44)
- Šaman
- Člen | 2668
Podědíš si vlastní třídu
ModelForm extends Nette\Application\UI\Form
, které předáš
$model
(nebo databázi, nebo prostě něco, co potřebuje
k práci).
Buď ho předáš v konstruktoru (ale to způsobuje problémy při
vytváření), takže lepší je použít setter injection a ve verzi
2.1 přímo injector, o nastavení se postará autowiring. Předpokládám,
že formuláře vytváříš pomocí továrničky v configu, jinak ten model
injectneš ručně v továrně v presenteru.
Editoval Šaman (31. 8. 2013 0:02)
- enumag
- Člen | 2118
Opět si neodpustím doporučit spíše továrny než dědičnost. To současně řeší i použití modelu:
class WhateverFormFactory extends \Nette\Object
{
/**
* @var \WhateverRepository
*/
private $repository;
public function __construct(\WhateverRepository $repository)
{
$this->repository= $repository;
}
public function create()
{
$form = new \Nette\Application\UI\Form;
// define fields using $this->repository
$form->onSuccess[] = $this->formSuccess;
return $form;
}
public function formSuccess(\Nette\Application\UI\Form $form) {
//...
}
}
services:
- WhateverFormFactory
Inject továrny v presenteru si díky Kdyby/Autowired ušetřím:
class WhateverPresenter extends BasePresenter
{
/**
* @return My\Awesome\Datagrid
*/
protected function createComponentWhateverForm($name, WhateverFormFactory $factory)
{
return $factory->create();
}
}
Editoval enumag (31. 8. 2013 0:25)
- Šaman
- Člen | 2668
No, po naší minulé
diskuzi jsem předělal dědičnost na továrny, ale tohle je podle mého
správné použití dědičnosti, protože nově vzniklá třída
ModelForm
skutečně rozšiřuje možnosti předka a přitom to
není konfugurování konkrétní instance.
Následně si nakonfiguruji konkrétní formulář pomocí továrny.
Ale pokud by bylo potřeba předávat například konkrétní repozitář, tak samozřejmě nemá smysl vytvářet ModelForm (já mám model jako service locator, takže se z něho dostanu do všech veřejných metod modelu), ale rovnou se vytvoří v továrně konrétní formulář a předá se mu příslušný repository/connection/servise/cokoliv.
Editoval Šaman (31. 8. 2013 0:53)
- enumag
- Člen | 2118
@Šaman: To plyne čistě z toho že máš model jako service locator (což taky není best practice). Sám říkáš že když by bylo třeba předávat konkrétní instanci jako já v příkladu výše tak dědičnost nemá smysl. Nevidím ale důvod předávat formuláři cokoli – vytvoření, validaci i zpracování formuláře dělám v továrně kam si závislosti injectnu, samotný formulář na žádné třídy modelu sahat nemusí.
@Myiyk: To s těmi jazyky jsem po pravdě nepochopil… Zkus to upřesnit pokud pořád nevíš jak. ;-)
- Vojtěch Dobeš
- Gold Partner | 1316
Mám dojem, že se stále opakuju, ale což takto :) ?
class CategoryForm extends Nette\Application\UI\Control
{
private $database;
public function __construct(Nette\Database\Connection $database)
{
parent::__construct();
$this->database = $database;
}
protected function createComponentForm()
{
$form = new UI\Form;
// $this->database is ready here.
$form->onSuccess[] = $this->processForm;
return $form;
}
public function processForm($form)
{
// $this->database is ready here too.
}
}
U toho přístupu s factory
mi přijde zvláštní
pojmenování, ale uznávám, že to řeší kupu problémů taky.
- Vojtěch Dobeš
- Gold Partner | 1316
Komponentu lze jako ne-službu zaregistrovat do configu též s využitím
ICategoryFormFactory
interfacu. Pak stačí vyžadovat tento
interface jako závislost v presenteru a v továrničce zavolat
return $this->categoryFormFactory->create();
.
- Filip Procházka
- Moderator | 4668
Dovolil jsem si to sepsat do pla.nette best practise jak psát formulářové komponenty. Doufejme že to Davídek brzy nahodí na web ;)
- Filip Procházka
- Moderator | 4668
@enumag
- to je pravda pouze za předpokladu že má soubor namespace, což tady nemá
- proč to nefixneš? :)
- Myiyk
- Člen | 321
Díky za rady, druhé řešení z pla.nette best practise jak psát formulářové komponenty vypadá dobře, pokusím se to rozjet.
- Myiyk
- Člen | 321
Hmm, tak nastal problém Class AdminModule\ICategoryFormFactory used in service ‚27_AdminModule_ICategoryFormFactory‘ has not been found or is not instantiable.
services:
- AdminModule\ICategoryFormFactory
namespace AdminModule;
use ...
class CategoryForm extends Control
{
...
}
interface ICategoryFormFactory
{
/** @return \AdminModule\CategoryForm */
function create();
}
Soubor s tou třídou a rozhraním (v jednom souboru je obojí) se ale includuje.
Takže chyba musí být v is not instantiable. Ale nechápu co to znamená. Co ten interface musí jako splňovat?
- Myiyk
- Člen | 321
díky, funguje to
@Filip Procházka: do best-practise-formulare-jako-komponenty se nejspíš vloudila chyba
- jetpack
- Člen | 71
Tak nevím jestli je někde něco blbě, ale podle návodu: https://github.com/…ponenty.texy
mi to u tohohle kódu:
<?php
$form->onSuccess[] = function (UI\Form $form) {
if (!$form->isValid())
return;
$this->flashMessage('Děkujeme...');
$this->redirect('this');
};
?>
háže chybu: Using $this when not in object context což je logické.
Jako použil jsem to tak:
<?php
$presenter = $this->getPresenter();
$form->onSuccess[] = function (UI\Form $form) use ($presenter) {
if (!$form->isValid())
return;
$presenter->flashMessage('Děkujeme...');
$presenter->redirect('this');
};
?>
Editoval jetpack (22. 10. 2013 15:27)