Jak správně napsat signál, který potřebuje určité parametry

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
joe
Člen | 313
+
0
-

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
+
+5
-

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)

joe
Člen | 313
+
0
-

Díky, to se bude určitě hodit :) Podle anotací to pak bude hodně návykové… Ještě se nabízí ale otázka, jestli je šikovné takto omezovat signály pro určité akce – jestli to vůbec dává smysl (?)

David Kudera
Člen | 455
+
0
-

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…

enumag
Člen | 2118
+
+1
-

@DavidKudera Používám v principu totéž akorát tu anotaci u komponent striktně vyžaduju abych na ni někde nezapomněl. U komponent kde to nevadí uvedu jako hodnotu té anotace hvězdičku.

bazo
Člen | 620
+
0
-

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
+
0
-

@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
+
0
-

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
+
0
-

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)