{widget test} ← mel by umirat na neimplementovanem rozhrani ITemplate

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

Ahoj,

používám NetteFramework-0.9.3-PHP5.2, ve kterém jsem si vytvořil šablonu volající komponentu test, následujícím způsobem:

{widget test}

Framework mi v presenteru zavolá metodu createComponentTest() ze které vrátím vytvořenou třídu/komponentu Test, následovně:

<?php
protected function createComponentTest() {
	return new Test();
}
?>

Pokud třída Test neimplementuje rozhraní IComponent, framework vyhodí výjimku Component with name ‚test‘ does not exist. a to díky kusu kódu v souboru Nette/ComponentContainer.php na řádku 144 který ověří, zda-li komponenta implementuje rozhraní IComponent a pokud ne, tak ho nevloží do pole komponent:

<?php
if (!isset($this->components[$name])) {
	$component = $this->createComponent($name);
	if ($component instanceof IComponent && $component->getParent() === NULL) {
		$this->addComponent($component, $name);
	}
}
?>

Potud je vše v pořádku. Problém nastává v následujícím případě. Šablonovací systém přeloží příkaz {widget test} na <?php $control->getWidget("test")->render() ?>, přičemž rozhraní IComponent neobsahuje metodu render(), takže jakmile se skript dostane na volání této metody v šabloně skončí fatal errorem, přitom bych očekával vyhození výjimky, obdobně jako v předchozím případě.

Pokud metoda ComponentContainer::getComponent() vždy vrací komponentu, u které bude volána metoda render(), žřejně bych rozšířil řádek 144 o kontrolu rozhraní ITemplate, které inkriminovanou metodu obsahuje. Pokud ne, kontrola by měla být zřejmě někde jinde (v metodě getWidget()?).

Rozšířená kontrola:

<?php
if (!isset($this->components[$name])) {
	$component = $this->createComponent($name);
	if ($component instanceof IComponent && $component instanceof ITemplate && $component->getParent() === NULL) {
		$this->addComponent($component, $name);
	}
}
?>

S frameworkem se teprve seznamuji, takže nechám rozřešení na laskavém čtenáři.

p.s. teď koukám, že přidání této podmínky by si vynutilo i úpravy jinde ve frameworku, například přidání ITemplate ve tříde /Nette/Forms/Form, která sice obsahuje metodu render(), ale v definici neimplementuje rozhraní ITemplate ani ždáný z jejích předků.

Ondřej Mirtes
Člen | 1536
+
0
-

Kdysi mě napadlo, že by měla být někde vynucena metoda render(), např. pomocí rozhraní IControl (ITemplate s tím má málo společného), ale tu by nesplňoval ani Presenter.

Vem si, že můžeš po potomku třídy Control (na kterém to makro widget voláš) chtít existenci nějaké jiné metody, než té s názvem render. Widget makro umožňuje třeba i tento zápis:

{widget komponenta:test}

čímž se zavolá metoda renderTest(). Anebo můžeš pomocí widget makra předávat parametry:

{widget komponenta test}

čímž se zavolá metoda render('test'), takže by PHP zařvalo, že hlavička metoda není kompatibilní s tou v interface.

vkuzel
Člen | 15
+
0
-

Ahoj, díky za info. Rozšířené volání widgetu jsem si neuvědomil.

Přesto by se možná framework mohl vyjádřit trochu jasněji, co se týče chyby. Pokud neimplementuju rozhraní IComponent, tak nedostanu hlášku, že komponenta není správná, že nemá správné rozhraní, ale napíše mi to, že neexistuje. A když neimplementuju metodu render(), tak to skončí fatalem na neexistující metodě.

Líbily by se mi hlášky jako, „Komponenta xxx musí implementovat rozhraní IComponent“, případně „Komponenta xxx musí mít metodu render()/renderCokoli()“ (dalo by se kontrolovat třeba pomocí funkce method_exists()), člověk pak bude hned vědět kde je problém. V současném stavu musím i v kódu frameworku hledat, kde je chyba, ale je to jenom maličkost.

Ondřej Mirtes
Člen | 1536
+
0
-

Jo, to už jsem sám reportoval.