Vylepšená továrnička: create<componentName>($name)

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Jan Tvrdík
Nette guru | 2595
+
0
-

Poznámka: je součástí frameworku od verze 0.9

Vytahuji vylepšenou továrničku, protože mi přijde škoda, že zapadla.

protected function createComponent($name)
{
	if (String::lower($name) === 'component') {
		return NULL;
	}

	$method = 'create' . $name;

	if (method_exists($this, $method)) {
		$component = call_user_func(array($this, $method));

		if ($component instanceof IComponent && $component->getParent() === NULL) {
			$this->addComponent($component, $name);

		} elseif ($component->getParent() === NULL) {
			is_callable(array($this, $method), TRUE, $textual);
			throw new InvalidStateException("Function '$textual' must return instance of IComponent");
		}

	} else {
		parent::createComponent($name);
	}
}

Editoval Jan Tvrdík (3. 8. 2013 15:41)

PaBi3
Bronze Partner | 62
+
0
-

Ja by som navrhol naozaj len takú kozmetickú úpravu a tou je výmena pomalšieho String::lower() za rýchlejšie strtolower(). Veď kto už použije v názve komponent diakritiku s veľkými písmenami?

nAS
Člen | 277
+
0
-

Je vůbec nějaký důvod, proč se tahle verze nepoužije v distribuci? Podle mě je výrazně lepší.

Honza Marek
Člen | 1664
+
0
-

Taky by se teoreticky u komponenty s názvem component mohla zavolat metoda parent::createComponent. Otázka je, jestli to něco řeší, když tahleta továrnička stejně bude většinou v BasePresenteru.

Inza
Člen | 330
+
0
-

Je tahleta továrníčka už v Nette/Extras v doku? Pokud ne, dáte ji tam pls?

Honza Marek
Člen | 1664
+
0
-

To je otázka, co třeba tam dát tuhletu skoro stejnou? :-D

/**
 * Create component using create{Name} method
 * @param string $name
 */
protected function createComponent($name) {
	$method = "create" . $name;

	if (method_exists($this, $method) && strtolower($name) !== "component") {
		$component = call_user_func(array($this, $method), $name);

		if ($component instanceof IComponent && $component->getParent() === NULL) {
			$this->addComponent($component, $name);
		}

	} else {
		parent::createComponent($name);
	}
}
jasir
Člen | 746
+
0
-

Jenom chci nahlásit, že supertovárnička je boží.

Společně s novým macrem {widget} (které odstraní přebytečné render… metody, ve kterých se jen plnila template komponentami) se některé prezentery smrsknou
jen na createMyControl() metody, coz je fakt jako cool.

Honza Kuchař
Člen | 1662
+
0
-

Proč tahle perfektní věc ještě není v distribuci?

romansklenar
Člen | 655
+
0
-

Protože není problém udělat CTRL + C a CTRL + V do BasePresenteru nebo BaseControlu, když většinou stejně nějaký základní presenter je? :)

Továrnička createComponent je jen obecný mechanismus a neurčuje konkrétní implementaci. Jestli si to člověk naimplementuje přes switche, podmínky nebo přes toto je přece jen čistě na něm. Začátečníky by mohlo volání callbacků dost zmást, proto si myslím že je i dobře, že to není v distribuci.

Honza Marek
Člen | 1664
+
0
-

Stejně jako by je mohlo zmást volání action{Action} :)

Ale přišel jsem na jiné proti… Muselo by se každému vysvětlit, aby se nepokoušel zavolat třeba $this->getComponent("template"), což pravda normálně nikoho ani nenapadne.

jasir
Člen | 746
+
0
-

romansklenar napsal(a):
Začátečníky by mohlo volání callbacků dost zmást, proto si myslím že je i dobře, že to není v distribuci.

Mě se zdá, že by to začátečníky určitě nemátlo, protože pak by „Návod na použití component v presenteru“ scvrkl na toto:

  1. Pro každou komponentu, kterou chceš použít v presenteru, vytvoř metodu createMyControl (nebo pro formuláře createMyForm), která vytvoří a vrátí nakonfigurovanou komponentu/formulář
  2. V template vykresli komponentu pomocí {control MyForm} nebo {wiget MyControl:specialRender}
  3. Pokud je zapotřebí dále manipulovat s komponentami například v renderView(), komponentu získáte pomocí $this->getControl('myForm')

Presenter se tedy za pomoci {widget} a této továrničky smrskne (v ideálním případě) do metod
createMyControl()

Honza M. napsal(a):
Ale přišel jsem na jiné proti… Muselo by se každému vysvětlit, aby se nepokoušel zavolat třeba $this->getComponent("template"), což pravda normálně nikoho ani nenapadne.

Dobrá připomínka, jméno komponenty ‚template‘ by v ‚createMyControl()` mělo být asi zakázané stejně jako 'component‘.

Editoval jasir (6. 7. 2009 19:31)

PetrP
Člen | 587
+
0
-

Dale existuje jeste createRequest.

Co kdyby jsme se vyhli vsech tehle problem s create*, protoze muzu v kodu pouzivat jeste dalsi createCokoli. A pouzit control<Name>, nebo component<Name>, nebo widget<Name> ?

Honza Marek
Člen | 1664
+
0
-

Asi nejvýstižnější by bylo createComponent<Name>, ale je to dost dlouhé.

jasir
Člen | 746
+
0
-

Honza M. napsal(a):

Asi nejvýstižnější by bylo createComponent<Name>, ale je to dost dlouhé.

Nebo zavést podtržítko…

<?php
protected function create_MyForm()
protected function create_MyWidget()
?>
  • Pro: větší přehlednost, jasné odlišení widgetových továrniček, nikdy se nebude tlouct s Nette
  • Proti: nehezké

Editoval jasir (7. 7. 2009 10:48)

PetrP
Člen | 587
+
0
-

jasir napsal(a):

Nebo zavést podtržítko…

To je proti Nette konvencím:

Coding standard

Functions and Methods

  • camelCase

Honza M. napsal(a):

Asi nejvýstižnější by bylo createComponent<Name>, ale je to dost dlouhé.

To je popravdě nejvýstižnější, otázka je: je to create skutečně nutné?

David Grudl
Nette Core | 8227
+
0
-

Do frameworku je lepší nové věci přidávat teprve v okamžiku, když ostatním tak moc chybí, že vyhrožují fyzickým útokem nebo úplatkem :-)

Ale jo, přidat by se to mohlo. Na úrovni ComponentContainer ne, na úrovni Control by to mohlo být ideální. Nicméně název by měl být dostatečně bezpečný a srozumitelný, což znamená createComponent<Name>.

David Grudl
Nette Core | 8227
+
0
-
Jod
Člen | 701
+
0
-

Super díky.
Nebolo by lepšie keby sa po zavolaní getComponent(‚grid‘) zavolalo createComponentGrid, miesto createComponentgrid? Alebo najprv skúsila zavolať prvá alternatíva a ak by sa nenašla tak druhá?

Honza Marek
Člen | 1664
+
0
-

Vždyť to volání metod není citlivé na velikost písmen.

Jod
Člen | 701
+
0
-

Potom už asi debilniem z tejto roboty :)

Honza Marek
Člen | 1664
+
0
-

Hlásim nespokojenost s implementací chytřejší továrničky.

Potřeboval bych metodám createComponent<Name> předávat parametr $name, protože některé moje komponenty potřebují již v továrničce být připojené k presenteru.

Př.:

// v presenteru
protected function createComponentEditForm($name) {
	new PageForm($this, $name);
}

// PageForm.php
class PageForm extends AppForm {
	public function __construct($parent, $name) {
		parent::__construct($parent, $name);

		// definice
		...

		$this["id"]->setValue = $this->presenter->getParam("id");
	}
}

Pokud by tenhle ne úplně šťastný příklad jako argument nestačil, zamyslím se a vymyslím lepší.

romansklenar
Člen | 655
+
0
-

Nepůjde to získat přes reflection z názvu metody? Ikdyž chápu, že je to zbytečně složité.

LM
Člen | 206
+
0
-

Proč to $this["id"]->setValue() nezavolat až v attached?

// class PageForm
protected function attached($presenter)
{
	parent::attached($presenter);

        if ($presenter instanceof Presenter) {
		$this["id"]->setValue = $presenter->getParam("id");
	}
}

Editoval LM (10. 7. 2009 18:07)

Jod
Člen | 701
+
0
-

Honzo, keď napíšeš createComponentEditForm, tak je jasné, že komponenta sa musí volať editForm, inak sa ti ta fnc nezavolá.
Ale tiež si myslím, že ten parameter by nebol na škodu, predsa je to krajšie keď tam dám $name, než napevno string. xixi =))

PetrP
Člen | 587
+
0
-

Jsem pro přidání, protože:

  • při případném přejmenování ho změním na méně místech ;]
  • méně psaní ;]
  • můžu používat továrny na některé componenty (nebo jejich častí nastaveni, vytvoření)
  • tahat si componenty z modelu (porad bojuju s myšlenkou ze tam např Form patří)
  • dostane název case sensitive tak jak jsem si ho napsal v getComponent
  • snadněji se mi migruje ze starého způsobu přes createComponent($name) { switch ($name) ....
  • něco si můžu například kešovat (nebo mít v sesions) v namespace podle nazvu componenty.
  • parametr bude nepovinej, takže ho použiju jen když ho potřebuju.

Editoval PetrP (11. 7. 2009 22:58)

Honza Marek
Člen | 1664
+
0
-

romansklenar napsal(a):

Nepůjde to získat přes reflection z názvu metody? Ikdyž chápu, že je to zbytečně složité.

Tak jsou i jiný problémy. Pokud čachruju se šablonou, když ještě neni control připojený k presenteru, tak potom šablona nezná proměnnou $presenter (tudíž nefunguje ani plink a tak).

David Grudl
Nette Core | 8227
+
0
-

Parametr $name se už předává

Honza Marek
Člen | 1664
+
0
-

díky

PetrP
Člen | 587
+
0
-

Juhuu ;]

pekinen
Člen | 29
+
0
-

A ten „stary“ zpusob pomoci switch se bude moci dal pouzivat??? Nebo si to mam rovnou radsi prepsat na zpusob novy?

Diky za info.

jasir
Člen | 746
+
0
-

pekinen napsal(a):

A ten „stary“ zpusob pomoci switch se bude moci dal pouzivat??? Nebo si to mam rovnou radsi prepsat na zpusob novy?

Určitě si můžeš vybrat… Ale nový způsob je přehlednější.