[Bug] InvalidStateException při nastavování defaultních hodnot
- mancze
- Člen | 58
Myslím, že poslední verze Nette (rev 285) obsahuje bug. Resp. co fungovalo, nefunguje :). Využívám vylepšené metody createComponent popsané zde: create<ComponentName>(). Následující kód vyhodí výjimku:
protected function createForm($name) {
$form = new AppForm();
//...
$form->setDefaults($defaults); // vyhazuje vyjimku!
}
InvalidStateException
Component is not attached to 'Presenter'.
Problém je, že výchzí hodnoty nelze pro dosud nepřidanou komponentu do
hiearchie nastavit. Přidáním řádku
$this->addComponent($form, $name);
před nastavování
výchozích hodnot je řešení, ale nabourává to přístup supertovárničky.
Navíc pro to není důvod, alespoň myslím.
Chyba se v revizi 254 (poslední má záloha) neobjevovala.
Editoval mancze (30. 4. 2009 13:21)
- kravčo
- Člen | 721
Je to zrejme spôsobené zmenou
v metóde Form::setDefaults, BC break to ale nie je, keďže pred touto
zmenou bolo treba volať setDefaults()
len na
neodoslanom formulári:
if (!$form->isSubmitted()) {
$form->setDefaults(array(
// ...
));
}
Čo je rovnaká logika ako v aktuálnej verzii, len sa táto podmienka
presunula do volania setDefaults()
.
Na tento problém som narazil i ja, keď som sa snažil odseparovať formuláre od prezenterov a nechať ich čisto v modeli – presne kvôli tomuto mi to celkom nešlo… Dá sa to riešiť nejako inak?
- jasir
- Člen | 746
kravco napsal(a):
Na tento problém som narazil i ja, keď som sa snažil odseparovať formuláre od prezenterov a nechať ich čisto v modeli – presne kvôli tomuto mi to celkom nešlo… Dá sa to riešiť nejako inak?
Napadá mě (a možná je to blbost) podědit si Form na MyForm – stejně něco podobného asi většina z nás dělá (?) – a v něm si přepsat setDefaults nějak takhle
<?php
private $_defaults
public function setDefaults($defaults)
{
$this->_defaults = $defaults;
}
public function attached($presenter)
{
parent::attached($presenter);
if($presenter instanceOf Presenter) {
$this->setDefaults($this->_defaults)
}
}
?>
Takto by se mělo setDefaults volat až při připojení k prezenteru.
Nezkoušel jsem…
Podobně jako to děla AppForm
Editoval jasir (30. 4. 2009 15:17)
- mancze
- Člen | 58
jasir napsal(a):
Takto by se mělo setDefaults volat až při připojení k prezenteru. Nezkoušel jsem…
Zřejmě funkční, ale fuj řešení. Co mají výchozí hodnoty co dělat s tím, jesti je form připojený k Presenteru či nikoliv?
Na druhou stranu souhlasím s tím, jak setDefaults funguje – přednastavuje jen v případě neodeslaného formuláře.
- jasir
- Člen | 746
mancze napsal(a):
jasir napsal(a):
Takto by se mělo setDefaults volat až při připojení k prezenteru. Nezkoušel jsem…
Zřejmě funkční, ale fuj řešení. Co mají výchozí hodnoty co dělat s tím, jesti je form připojený k Presenteru či nikoliv?
Presenter poskytne informace o zaslání/nezaslání formuláře? Podobně, jako to dělá AppForm, pouze jsme ho rozšířili? No dobře, zavání to :)
- Honza Marek
- Člen | 1664
protected function createForm($name) { $form = new AppForm(); }
Nejjednodušší (i když lehce otravné) bude připojení formuláře k presenteru už v konstruktoru takhle:
$form = new AppForm($this, $name);
Na druhou stranu to ani nebude potřeba na konci vracet returnem.
- jasir
- Člen | 746
Honza M. napsal(a):
Nejjednodušší (i když lehce otravné) bude připojení formuláře k presenteru už v konstruktoru takhle:
$form = new AppForm($this, $name);
Na druhou stranu to ani nebude potřeba na konci vracet returnem.
Jo, v super továrničče to je tak
asi nejsnazší, na druhé straně jak psal kravco, možná by se přístup
přes attached()
dal použít pro tvorbu formulářů v rámci
modelů.
Editoval jasir (30. 4. 2009 16:10)
- Patrik Votoček
- Člen | 2221
Jak psal Honza M. tak bych to vyděl jako správné řešení. I když vytváření formuláře máš v modelu. Nevím jestly by to tam mělo být ale asi ano. Tak stejně když ten formulář vytváříš tak ho na 99% budeš chtít i vykreslit (vlastně asi na 100% – nenapadá mě důvod vytvářet formulář který se později nevykreslí.
A co ti brání pokud máš tvorbu formuláře v modelu řekněme:
<?php
class MyModel extends Model
{
public function createForm(...)
{
...
}
}
?>
Nevím proč nemít v parametrech $parent a $name, stejně by se dle mého názoru ‚bestpractice‘ formulář pojmenovat nějákým IDčkem. A když už víme že se bude vykreslovat tak mu předat i $parent (presenter nebo vykreslitelnou komponentu).
Taky nechápu proč by to mělo popírat smysl supertovárničky? Přece
když volás createComponent($name)
tak už máš dostupný
presenter/vykreslitelnou komponentu. Tak proč jí v továrničce to $this
nenapsat. Navíc jméno je u createComponent($name)
v parametru
name jako poviné tak proč to taky nepředat?
Nebo sem snad něco nepochopil?
Editoval vrtak-cz (30. 4. 2009 17:40)
- mancze
- Člen | 58
Osobně cítím vytvoření komponenty (ať již AppForm nebo cokoliv jiného) a její zařazení do hierarchie komponent jako dva oddělené kroky. Nelíbí se mi proto to mít v společně v jedné metodě.
Každopádně se přiznám, že jednoduché
$form = new AppForm($this, $name);
mne nenapadlo. Používám
obdobné řešení: $form = $this->spawnForm($name);
, které
vytvoří a vrátí samotnou instanci Formu už zařazeného do hierarchie.
- kravčo
- Člen | 721
vrtak-cz napsal(a):
Taky nechápu proč by to mělo popírat smysl supertovárničky? Přece když volás
createComponent($name)
tak už máš dostupný presenter/vykreslitelnou komponentu. Tak proč jí v továrničce to $this nenapsat. Navíc jméno je ucreateComponent($name)
v parametru name jako poviné tak proč to taky nepředat?
Iste, máš pravdu. Vyriešil som to tak ako popisuješ. Akurát sa mi to veľmi nepáči a nie je podľa mojich predstáv. To čo písal jasir vyzerá rozumne, bude to chcieť asi trochu doladiť (napr. dediť od AppFormu, keďže Form nemusí súvisieť s prezenterom). Vyskúšam to a podelím sa…