Presenter::extensionMethod se nepromítá do tryCall

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

Presenter::tryCall() volá jenom Presenter::getReflection()->hasMethod(). To je originální funkce z \ReflectionClass a předpokládám, že volá upravenou getMethods(). Nejsou v ní ale rozšíření z extensionMethod().

class CustomPresenter extends Presenter {}

$p = new CustomPresenter();
$p->extensionMethod('actionDynamic', callback(...));

// životní cyklus presenteru se poté při requestu `Custom:dynamic` dostane k:
$p->tryCall('actionDynamic', array());
// a na tom selže

První možnost je přidat do tryCall() ještě jednu podmínku, něco jako tohle.

Druhá možnost je upravit getMethods() (a tedy hasMethod?) tak, aby brala na vědomí i rozšíření. To by ale znamenalo, že Callback by musel získat další metodu getTargetReflection, což by byla MethodReflection/FunctionReflection toho callbacku (callback->reflection je teď jenom reflexe třídy callback).

Tohle využijí například komponenty, které potřebují nějakou akci (třeba kvůli ajaxu).

David Grudl
Nette Core | 8218
+
0
-

Upravit třídy reflexe nejde, hasMethod by ošálit šlo, ale getMethod ne, nelze vytvořit ReflectionMethod pro virtuální metodu. Podpora by tedy musela být cíleně v tryCall, jenže nemyslím, že by to byl krok správným směrem, s extension method je třeba zacházet opatrně.

Filip Procházka
Moderator | 4668
+
0
-

Osobně si nemyslím, že to je potřeba, bylo by to až moc magické. A určitě to, co chceš implementovat půjde i bez toho :)

Martin
Člen | 171
+
0
-

Zdravím. Nevím, jak jste to nakonec vyřešili, já mám pro provizorní rozchození právě dodělávané komponenty něco takového (samozřejmě ve výsledku to bude jinak):

	protected function tryCall($method, array $params)
	{
		$rc = $this->getReflection();
		if ($rc->hasMethod($method)) {
			$rm = $rc->getMethod($method);
			if ($rm->isPublic() && !$rm->isAbstract() && !$rm->isStatic()) {
				$rm->invokeNamedArgs($this, $params);
				return TRUE;
			}
		}
else if ($rc->getExtensionMethod($method)) {
    Nette\ObjectMixin::call($this, $method, $params);
    return TRUE;
}
		return FALSE;
	}

Byla by to příliš velká bezpečnostní díra, nebo proč to není vhodné používat? Mně by se to docela hodilo kvůli jednoduchému svázání handleru komponenty s callbacky v presenteru, ale už to holt začínám dotvářet jinak.

Editoval Martin (8. 4. 2011 1:40)

Martin
Člen | 171
+
0
-

Tak jsem to nakonec dovedl k funkčnosti bez přepisování TryCall. Ale je to takto správně (ve třídě poděděné od AppControl, aby fungoval parametr ?do=jmenoKomponenty-jmenoHandleru)?

	public function signalReceived($signal)
	{
		if ($signal === 'submit') {
             	return parent::signalReceived($signal);
		} else {
                 $method = $signal == NULL ? NULL : 'handle' . $signal;
                 $rc = $this->getReflection();
                 if ($rc->hasMethod($method)) {
                     $rm = $rc->getMethod($method);
                     if ($rm->isPublic() && !$rm->isAbstract() && !$rm->isStatic()) {
                             $presenter = $this->getPresenter();
                             $params = $presenter->getParam();
                             $rm->invokeNamedArgs($this, $params);
                             return TRUE;
                     }
                 }
         }

         throw new BadSignalException("There is no handler for signal '$signal' in class {$this->reflection->name}.");
}

Přijde mi to trochu jako drbání se pravou rukou za levým uchem. Proč se vlastně komponentě nepředávají parametry? U presenteru to nevadí, sám sobě si je dávat nemusí. Nebo se prostě s touto cestou vytváření aktivní komponenty v Nette záměrně nepočítá?

Editoval Martin (8. 4. 2011 3:23)

David Grudl
Nette Core | 8218
+
0
-

Proč se vlastně komponentě nepředávají parametry

Komponentně se parametry předávají. Selže to tehdy, pokud si přepíšeš kontruktor a nezavoláš parent::__construct()