Callback do jiné komponenty
- m.brecher
- Generous Backer | 871
Ahoj,
zkusil jsem ve formuláři nasměrovat callback onClick[] formuláře do jiné komponenty presenteru a nedaří se to:
Presenter:
final class ProjectPresenter extends AdminPresenter
{
public function createComponentEditImageForm(): Form
{
$form = new Form;
.......
$form->addSubmit('deleteButton', 'Smazat vše')
->onClick[] = [$this['dialog'], 'handleOpen'];
return $form;
}
}
Komponenta dialog v presenteru existuje a volaný handler také, nicméně to vyhazuje chybu:
ReflectionException #-1
Class "string" does not exist
Když volám handler komponenty mezikrokem přes handler presenteru, tak to funguje:
Presenter:
final class ProjectPresenter extends AdminPresenter
{
public function createComponentEditImageForm(): Form
{
$form = new Form;
.......
$form->addSubmit('deleteButton', 'Smazat vše')
->onClick[] = [$this, 'handleDialogOpen'];
return $form;
}
public function handleDialogOpen()
{
$this['dialog']->handleOpen('deleteImage');
}
}
Podle dokumentace PHP k callbackům by to fungovat mělo, je toto v Nette zakázané – volat ve formuláři handler jiné komponenty ? Nebo je nějaká chyba v mém kódu či ve Frameworku ?
Druhý dotaz mám jak předat v callbacku onClick[] nějaký parametr – to už je otázka spíš na PHP.
Mám použít něco jako:
$submitButton->onClick[] = [$object, 'method']($parameter);
Nabo nějak nahradit ‚method‘ něčím jako anonymní funkcí či arrow funcí?
Díky všem přdem za rady.
- dakur
- Člen | 493
@mbrecher Ad handle – to nejde. Z dokumentace:
Signál se vždy volá na aktuálním presenteru a view, tudíž není možné jej vyvolat na jiném presenteru nebo view.
Týká se to i komponent. Presenter je taky komponenta. Signál (tedy handle) se vždy váže ke své komponentě.
Proč si neuděláš v presenteru handleDeleteAll()
?
Editoval dakur (30. 8. 2022 9:19)
- mystik
- Člen | 312
Správné řešení je to volat přes presenter nebo nějakou nadřazenou komponentu a ne aby se komponenty volaly napřímo.
Jinak k tomu parametru to takhle použít nejde, protože callbacku se parametry předávají v okamžiku volání. Takže je řešení si udělat anonymní funkci.
$submitButton->onClick[] = function() use ($object, $method) { $object->method($parameter); });
Jde totiž o to, že callbacky dostávají parametry od volajícího, které mohou používat. Např.:
$submitButton->onClick[] = function(SubmitButton $submittedBy) use ($object, $method) { $object->method($submittedBy->getCaption()); });
Editoval mystik (30. 8. 2022 10:32)
- m.brecher
- Generous Backer | 871
@dakur
Ahoj, díky za komentář, ano s tím, že se signál volá na aktuálním presenteru a view souhlasím a nesnažím se to dělat jinak. Problém nemám s volání signálu, ale s callbackem eventHandleru formuláře $submitButton->onClick[]. V tomto případě odesílám formulář submit tlačítkem „Smazat“, odešle se formulář post metodou jako signál, který je interně ve formuláři zabudován v hidden prvku, ve formuláři se automaticky Frameworkem vykresluje toto:
<input type="hidden" name="_do" value="editImageForm-submit">
Nejsem znalec, ale předpokládám, že položka _do je speciální formulářový signál, který po zpracování zase vykreslí původní presenter a původní view. Takže si myslím, že problém mám jinde než tam, že bych volal signál na jiném presenteru nebo view – ani to asi nejde.
@mystik ve svém komentáři odpovídá přesně na to co je problémem – jak správně volat ten callback.
Ale díky za komentář.
- m.brecher
- Generous Backer | 871
@mystik
Ahoj, díky za navedení správným směrem – použít pro callback anonymní/arrow funkci – funguje to. Po prozkoumání problému jsem objevil příčinu proč nešlo volat komponentu v callbacku. Mezi automatickým injektováním do callbacku (eventHandleru) a očekávaným vlastním parametrem v komponentě byl konflikt.
Formulář – navěšení callbacku
$submitButton->onClick[] = [$presenter, 'buttonClickHandler'];
Presenter – callback přijímá parametry dle autowiringu:
public function buttonClickHandler(ArrayHash $values) // funguje - parametr je v souladu s autowiringem
{
.......
}
Presenter – callback s vlastním parametrem:
public function buttonClickHandler(ArrayHash $values, string $myParam)
{
.....
// Nette vyhodí výjimku, předat vlastní parametr $myParam autowiring neumožňuje
}
Pro předání vlastního parametru do callbacku je potřeba autowiring obejít:
- volat handler přes jinou metodu:
$submitButton->onClick[] = [$this, 'buttonClickHandlerBridge'];
public function buttonClickHandlerBridge(ArrayHash $values) // Nette injektuje
{
$myParam = 'deleteImage';
$this->buttonClickHandler($myParam, $values); // ručně předáme vlastní parametr + injektovaný
}
public function buttonClickHandler(string $myParam, ArrayHash $values)
{
...........
}
- anonymní funkce, injektované parametry se předají jako parametry funkce, vlastní parametr pomocí use():
$submitButton->onClick[] = function(ArrayHash $values) use($myParam) { $this->buttonClickHandler($values, $myParam); };
- arrow funkce (nejjednodušší varianta) – předá injektované i vlastní parametry
$submitButton->onClick[] = fn(ArrayHash $values) => $this->buttonClickHandler($values, $myParam);
Objekt, který voláme v callbacku může být presenter nebo komponenta presenteru:
$submitButton->onClick[] = fn(ArrayHash $values) => $this['someComponent']->buttonClickHandler($values, $myParam);
Takhle, když si to člověk v hlavě setřídí, tak je to skoro triviální:
- jako callback lze použít metodu presenteru nebo komponenty presenteru
- je potřeba respektovat autowiring a nepředávat vlastní parametry
- v případě, že je potřeba předat vlastní parametr, tak použít arrow funkci