Převod formuláře ve stylu nette 0.8 do nového Nette
- miho
- Člen | 13
Ahoj. Převzal jsem apku psanou v Nette 0.8. Potřebuji ji dostat do novější verze Nette. Je v ní hromada (100+) formulářů udělaných „postaru“:
public function renderLogin()
{
$form = new Form;
$form->addText('name', 'Jméno:')->addRule(Form::FILLED, 'Zadejte jméno');
$form->addPassword('password', 'Heslo:')->addRule(Form::FILLED, 'Zadejte heslo');
$form->addSubmit('login', 'Přihlásit');
if ($form->isSubmitted()) {
if ($form->isValid()) {
$values = $form->getValues();
//udělej něco
}
}
$this->template->form = $form;
}
Když to budu všechno předělávat na komponenty, tak se z toho zblázním, takže se pokouším to ochcat. Když formulář ukotvím přes $form->setParent($this); tak to po odeslání hodí There is no handler for signal ‚-submit‘ in class App\Presenters\HomepagePresenter. Což dává smysl, form samotný handler nemá… ale moc mi to nepomáhá když chci, aby handloval přímo presenter. Je nějaká šance to v novém Nette rozjet v této podobě? Nebo alespoň tak, že vytvoření formu nechám jak je a handler onSuccess hodím mimo? Zkoušel jsem $form->onSuccess[] = [$this, ‚fakeHandler‘]; a přidat public function fakeHandler(UI\Form $form, $data): void { } ale hodí to stejnou chybu. Když použiju pro ukotvení $this->addComponent($form,‚loginform‘); tak to hodí The signal receiver component ‚loginform‘ is not found.
- Marek Bartoš
- Nette Blogger | 1274
addComponent()
je správně pro přidání komponenty do stromu
a zbavíš se tím chyby s handlerem. Problém ale je, že signál se
zpracovává mezi action*
a render*
, přidávat
definici formuláře v renderu je tedy pozdě. Přesuň definici do
actionLogin()
a mělo by ti to fungovat.
onSuccess
nemusíš řešit, to isSubmitted()
a
isValid()
je v podstatě jen alternativní zápis.
Editoval Marek Bartoš (28. 3. 2023 18:05)
- miho
- Člen | 13
Zkoušel jsem také
public function renderLogin()
{
$form = new Form;
$form->addText('name', 'Jméno:')->addRule(Form::FILLED, 'Zadejte jméno');
$form->addPassword('password', 'Heslo:')->addRule(Form::FILLED, 'Zadejte heslo');
$form->addSubmit('login', 'Přihlásit');
$form->onSuccess[] = function (Form $form, \stdClass $values): void {
//...
};
$form->setParent($this);
$this->template->form = $form;
}
ale se stejným výsledkem: There is no handler for signal ‚-submit‘ in class App\Presenters\HomepagePresenter. Hrozná cíťa ta Nette ;-)
- m.brecher
- Generous Backer | 871
@miho
Když to budu všechno předělávat na komponenty, tak se z toho zblázním, takže se pokouším to ochcat.
Píšu z hlavy, takže bez záruky, ale myslím, že komponenty z toho dělat nemusíš, formuláře fungují pořád postaru i bez komponent a bez factory rovnou v presenteru.
Co možná už je jinak je metoda isValid()? Našeptávač IDE me našeptal metodu $form->isSuccess()
Tak to zkus takhle – jednoduše vyhodit isSubmitted() + isValid() a místo toho dej isSuccess() ;) mohlo by to řešit problém.
if ($form->isSuccess) {
$values = $form->getValues();
//udělej něco
}
Editoval m.brecher (28. 3. 2023 18:30)
- m.brecher
- Generous Backer | 871
@miho
Napsal jsem to blbě, sorry,
problém je v tom, že chceš na formuláři nastavit handler v době, když už je po handlování = už proběhl signal processing presenteru !!
Můžeš metody renderSomeForm() přepsat na actionSomeForm() (action proběhne před zpracováním signálu) + místo ->isSuccess() použít korektní callback $form->onSuccess[] = function(…){…}
Mohou teoreticky nastat další komplikace, potom nezbyde než korektně napsat jak je doporučeno v dokumentaci createComponentSomeForm(). Zkus a uvidíš.
Editoval m.brecher (28. 3. 2023 18:30)
- m.brecher
- Generous Backer | 871
@miho
Nějak takhle:
public function actionLogin()
{
$form = new Form;
$form->addText('name', 'Jméno:')->addRule(Form::FILLED, 'Zadejte jméno');
$form->addPassword('password', 'Heslo:')->addRule(Form::FILLED, 'Zadejte heslo');
$form->addSubmit('login', 'Přihlásit');
$form->onSuccess[] = function (Form $form, \stdClass $values): void {
// dělej něco ...
};
$this->template->form = $form;
}
Obejdeš tím elegantní koncept vytváření komponent až když jsou potřeba pomocí createComponent<Component>, ale když jsou toho stovky a není čas :). Fungovat by to mělo, formulář se vytvoří podle akce i kdyby se nakonec nevykresloval.
edit
Tak mě došlo, že formulář nebude v hierarchii komponent presenteru – právě proto, že jsme obešli createComponent<Component>() :(.
Tady už moje představivost končí, napadá mě ještě $presenter->addComponent(), to je poslední možnost:
public function actionLogin()
{
$form = new Form;
$form->addText('name', 'Jméno:')->addRule(Form::FILLED, 'Zadejte jméno');
$form->addPassword('password', 'Heslo:')->addRule(Form::FILLED, 'Zadejte heslo');
$form->addSubmit('login', 'Přihlásit');
$form->onSuccess[] = function (Form $form, \stdClass $values): void {
// dělej něco ...
};
$this->addComponent($form, 'loginForm');
$this->template->form = $form; // tohle je otázka jestli nevyhodit, záleží jak v šabloně voláš $form
}
Editoval m.brecher (28. 3. 2023 18:37)
- miho
- Člen | 13
Tahle verze:
public function actionLogin() {
$form = new Form;
$form->addText('name', 'Jméno:')->addRule(Form::FILLED, 'Zadejte jméno');
$form->addPassword('password', 'Heslo:')->addRule(Form::FILLED, 'Zadejte heslo');
$form->addSubmit('login', 'Přihlásit');
$this->addComponent($form,'loginform');
if ($form->isSubmitted()) {
if ($form->isValid()) {
$values = $form->getValues();
//...
}
}
$this->template->form = $form;
}
public function renderLogin()
{
}
funguje, do té podmínky se to zcela jistě dostane ale hodí to warning: User Warning Form was submitted but there are no associated handlers.
Editoval miho (28. 3. 2023 18:37)
- m.brecher
- Generous Backer | 871
@miho
User Warning Form was submitted but there are no associated handlers.
Ano, musíš to napsat jak jsem ti poslal $form->onSuccess[] = …, ono se to musí volat později !! Callback !! Ve fázi action není form zpracovaný a není succeeded !!
Editoval m.brecher (28. 3. 2023 18:40)
- m.brecher
- Generous Backer | 871
@miho
Tahle verze: … funguje, do té podmínky se to zcela jistě dostane …
Nedostane a nemůže dostat !!
Formulář je vytvořený jako objekt v RAM paměti na serveru, ale NENÍ připojen do stromu komponent presenteru! Presenter obdrží signál, ale nenajde formulář ani handler.
Tipoval bych, že aby to fungoval takhle jak to máš natvrdo v action<Action>() tak nejde obejít:
a) napsat to jako callback – jak jsem Ti poslal
b) ručně přidat $form do presenteru addComponent()
Editoval m.brecher (28. 3. 2023 18:45)
- Marek Bartoš
- Nette Blogger | 1274
Fajn, na warning u chybějícího onSuccess jsem zapomněl, ale není
pravda, že by to nefungovalo bez onSuccess :) Data z http requestu jsou
v action dostupná, formulář je připojený do stromu a zvládne si je
vytáhnout a Nette to správně validuje.
Warning je jen pro případ, kdy je úspěšné zpracování
opomněné úplně.
@mbrecher Chápu, že se snažíš pomoct, zkus to však trochu zkráceně a kontrolovat si, zda to co tvrdíš tak skutečně je :) addComponent() tam má, nic jiného třeba není.
Editoval Marek Bartoš (28. 3. 2023 18:55)
- miho
- Člen | 13
Díky za rady @Marek Bartoš a @m.brecher – určitě by to takhle šlo ale bylo by to více přepisování. Finální, extrémně hnusná… ale funkční verze zarnuje nicnedělající falešný handler a skutečný handler v action (do těch podmínek se to dostane, takže jsou splněny:
public function fakeHandler(UI\Form $form, $data): void {
}
public function actionLogin() {
$form = new Form;
$form->addText('name', 'Jméno:')->addRule(Form::FILLED, 'Zadejte jméno');
$form->addPassword('password', 'Heslo:')->addRule(Form::FILLED, 'Zadejte heslo');
$form->addSubmit('login', 'Přihlásit');
$form->onSuccess[] = [$this, 'fakeHandler'];
$this->addComponent($form,'form');
if ($form->isSubmitted()) {
if ($form->isValid()) {
$values = $form->getValues();
//----
}
}
$this->template->form = $form;
}
public function renderLogin()
{
}
zkrátka je třeba to oblbnout, aby to dělalo to, co člověk potřebuje, tedy chová se to přesně jako MacOS ;-)
BTW takové zbytečné změny jako že už není $this->user->authenticate ale $this->user->login atd, přičemž příklady na netu uvádějí tu první variantu, to dělá @DavidGrudl schválně aby naštval lidi, nebo to je jen náhoda? ;-)
Editoval miho (28. 3. 2023 18:56)
- Marek Bartoš
- Nette Blogger | 1274
$form->onSuccess[] = function() {}
bude fungovat stejně
dobře.
A fakt se to nedělá proto, aby byli lidi naštvaní. Dělá se to proto, že v tom lidi často chybovali nebo funkci pochopili špatně. A jestli nechceš být další s banem, tak bude příště vhodnější dotaz, proč to tak funguje, bez souzení jak se autor snaží dělat naschvály.
- David Grudl
- Nette Core | 8227
Jaké příklady na netu uvádí tu první variantu?
(btw původní metoda tam je)
- Marek Bartoš
- Nette Blogger | 1274
Proto se postupuje po jednotlivých (x.y) verzích. Opravíš chyby, posuneš se dál. Ideálně s phpstanem a phpstan-deprecation-rules, které tě na všechny deprecations upozorní.
- miho
- Člen | 13
To bych musel několikrát pošoupnout verzi PHP a tím i knihoven a linuxu, který je pod tím (nebo to dát do dockeru). To zní děsivě.
Vypadá to, že tenhle task mě naučí dělat spoooustu prasáren. Hele na tu krásu:
class dibi {
private static \Dibi\Connection $db;
function __construct(\Dibi\Connection $db) {
self::$db = $db;
}
public static function query(...$params) {
$args = func_get_args();
return call_user_func_array([self::$db,'query'], $args);
}
}
A už nemusím přepisovat 478 výskytu dibi::query různě rozesetých v kódu a přidávat přes DI databázi do desítek tříd v modelu ;-)
- David Grudl
- Nette Core | 8227
Jestli je někde použité authenticate(), tak to opravím. Jen mi musíš říct kde.
- Marek Bartoš
- Nette Blogger | 1274
To bych musel několikrát pošoupnout verzi PHP a tím i knihoven a linuxu, který je pod tím
Stačí ti spustit samotný phpstan na jiné verzi php. Kód phpstan nespouští, takže je to safe.