Jak správně napsat signál, který potřebuje určité parametry
- joe
- Člen | 313
Ahoj,
mám trošku teoretický dotaz, jakým způsobem psát signály pro konkrétní akce, třeba v presenterech. Pokud mám akci vedoucí na detail, například:
public function actionDetail($id) {...}
a řeknu si, že v detailu položky chci (na stránce) umožnit přidání položky do oblíbených, vytvořím signál a vídal jsem kódy jako:
public function handleAddToFavorite() {
$id = $this->getParameter('id');
...
}
Kde je všechno v pořádku, ale až na situaci, kdy někdo zavolá signál
na jiné akci – dojde k chybě a do proměnné $id
se nic
nedostane. Je možné nějak elegantně říci, že tento signál lze volat jen
při určité akci? A nebo je nejlepším řešením přímo signálu dát
úplně všechny potřebné parametry (ikdyž se budou v některých
případech duplikovat)?
(Jde mi o best practice, pochopitelně můžu v každém signálu kontrolovat, jestli jsou všechny hodnoty z požadavku naplněny, ale vsadim se, že by se na to někde zapomnělo)
Díky
- David Kudera
- Člen | 455
No best practice určitě nevím, ale kdysi jsem si vytvořil takovou trikovačku, která kontroluje, jestli jsou signály a komponenty použity z povolené akce. Nijak jsem ale nezjišťoval, jestli je něco lepšího nebo ne, takže to používám do teď a funguje to hezky :-)
V base presenteru mám:
abstract class BasePresenter extends Presenter
{
// není potřeba, pokud nepoužíváš kdyby/autowired
/*use AutowireComponentFactories {
AutowireComponentFactories::createComponent as protected kdybyCreateComponent;
}*/
/**
* @param \Nette\Reflection\Method $element
* @throws \Nette\Application\ForbiddenRequestException
*/
public function checkRequirements($element)
{
if ($element instanceof Method) {
$method = $element->getName();
// process handle methods with @action annotation
if (Strings::match($method, '/^createComponent|handle/') !== null && $element->hasAnnotation('action')) {
$action = explode(', ', $element->getAnnotation('action'));
if (!in_array($this->getAction(), $action)) {
throw new ForbiddenRequestException;
}
}
}
}
/**
* @param string $name
* @return \Nette\ComponentModel\IComponent
*/
protected function createComponent($name)
{
$method = 'createComponent'. ucfirst($name);
$rc = $this->getReflection()->getMethod($method);
$this->checkRequirements($rc);
//return $this->kdybyCreateComponent($name); // jen pro kdyby/autowired
return parent::createComponent();
}
}
no a potom už jen přidávám @action
anotace k signálům a
komponentám:
class SomePresenter extends BasePresenter
{
/**
* @action signIn
* @return \App\Components\User\SignInForm\SignInFactory
*/
protected function createComponentSignInForm()
{
}
/**
* @action default, browse, detail
* @param int $id
*/
public function handleAddToFavorites($id)
{
}
}
možná by bylo vhodný to přesunout někam jinam a asi ani nevypadá moc hezky to ruční volání checkRequirements
Editoval David Kudera (12. 12. 2014 8:30)
- David Kudera
- Člen | 455
Nad tím jsem nijak moc nepřemýšlel. Původně jsem to napsal jen pro komponenty a když už jsem to měl takhle napsaný, tak jsem si řekl, že vlastně signály používám, stejně jako komponenty, jen v některých akcích, tak že bych to na mě mohl taky použít…
Minimálně mi to ošetří ty věci, o kterých jsi psal nahoře. Nestane se mi, že by to někdo zavolal např. z jiné akce, kde nebudou dostupné všechny parametry. To už mám totiž ověřené v action* metodě a signál pak přijme jen ty „další“ své parametry (nebo žádné).
Takže asi tak nějak jak jsem psal já a nebo si předávat všechny parametry. Nakonec jde ale stejně jen o presentery a třeba já už ani v presenterech moc signálů nemám, vlastně skoro žádné, protože všechno je v komponentách a tam to řešit nemusím. Co ale budu zanedlouho řešit, je to, abych zkusil nějak udělat ze signálů traity a ty mohl vložit do dalších komponent, protože třeba přidání do oblíbených mám z více různých komponent…
- bazo
- Člen | 620
David Kudera napsal(a):
Nad tím jsem nijak moc nepřemýšlel. Původně jsem to napsal jen pro komponenty a když už jsem to měl takhle napsaný, tak jsem si řekl, že vlastně signály používám, stejně jako komponenty, jen v některých akcích, tak že bych to na mě mohl taky použít…
Minimálně mi to ošetří ty věci, o kterých jsi psal nahoře. Nestane se mi, že by to někdo zavolal např. z jiné akce, kde nebudou dostupné všechny parametry. To už mám totiž ověřené v action* metodě a signál pak přijme jen ty „další“ své parametry (nebo žádné).
Takže asi tak nějak jak jsem psal já a nebo si předávat všechny parametry. Nakonec jde ale stejně jen o presentery a třeba já už ani v presenterech moc signálů nemám, vlastně skoro žádné, protože všechno je v komponentách a tam to řešit nemusím. Co ale budu zanedlouho řešit, je to, abych zkusil nějak udělat ze signálů traity a ty mohl vložit do dalších komponent, protože třeba přidání do oblíbených mám z více různých komponent…
co tak spravit z tlacitka na pridanie do oblubenych komponentu, a tu si vytvarat v tych dalsich komponentach? cize signal nemusis riesit
- David Kudera
- Člen | 455
@enumag jo to je docela chytrý, asi to tak taky udělám, aby to bylo povinné ;-)
@bazo hele a tohle se mi taky líbí.. díky :-) nějak mě to vůbec nenapadlo, hlavně že jsem minulý týden šaškoval s předěláváním některých form kontejnerů na komponenty, aby mohli mít šablonu a tohle mě nenapadne… ale to už je OT, tak kdyžtak pardon
- petr.pavel
- Člen | 535
Mimochodem, parametry metody handle můžeš uvést rovnou do její definice.
<?php
public function handleAddToFavorite($id) {...}
?>
Jestli ti ale dobře rozumím @joe, vadí ti, že Nette nezařve, když v odkazu ten parameter neposkytneš. Tj. že vlastně všechny parametry metody handle jsou nepovinné ($id = null).
Pak by ale mělo být řešení přetížit si v presenteru signalReceived($signal), přes reflexi zjistit parametry metody a ověřit, že jsou všechny k dispozici.
Bohužel, logiku typu „Záznam s id $id neexistuje“ budeš muset řesit v startup(), abys ji nemusel duplikovat v action a handle. :-(
- JL
- Člen | 24
Ahoj, líbí se mi co navrhoval @DavidKudera, nicméně jak bych
zajistil stejnou funkcionalitu např. pro onSuccess handle? Rozšířením
Strings::match
? To mi pravděpodobně může matchnout i to co
bych nechtěl.
EDIT: To je vlastně možná hloupost, protože tuhle funkci volám typicky z createComponent() kde se to už řeší. Sám nevím jistě, ach jo :-)
Editoval JL (23. 9. 2015 14:31)