Enhancement: Co takhle create<componentName>($name)?
- mancze
- Člen | 58
Poznámka: je součástí frameworku od verze 0.9
Chtěl rozvést diskuzi o tom, zda by se továrnička na koponenty neměla posunout ještě o kousek dál.
Jde o to, že jsem kolikrát měl v metodě createComponent($name) switch, který mi jen rozhodil vytvoření komponent mezi funkce uzpůsobené pro vytvoření právě dané komponenty. Vedlo mne k tomu to, že jsem předtím měl v createComponent() obrovskej štrůdl kódu a mi se to nelíbilo :). Vypadalo to asi takto:
public function createComponent($name) {
switch ($name) {
case 'name1': $this->createName1($name); break;
case 'name2': $this->createName2($name); break;
/* ... a několik dalších komponent */
default: parent::createComponent($name); break;
}
protected function createName1($name) { /* vytvoří komponentu name1 */ }
protected function createName1($name) { /* vytvoří komponentu name2 */ }
To mne velice rychle omrzelo a namísto toho jsem v BasePresenteru uzpůsobil createComponent tak, že automaticky se snaží vyvolat create<$name>($name). Od té doby jsem navýsost spokojen a mám od továrničky pokoj (i když mne ještě trochu obtěžuje ten parametr $name, ale to se ještě dá tolerovat ;).
Nedávno mne začalo vrtat hlavou, zda bych se s tímto neměl podělit s ostatními a jejich názory na takový přístup. Není to nic objevného, ale přeci jen se mi to zdá víc Netťácké, no ne? Když už se nám Nette stará automaticky o mapování akcí, pohledů, tak proč ne rovnou i vytváření komponent? Zase bychom měli o starost méně :). Co myslíte?
- Jan Tvrdík
- Nette guru | 2595
jasir napsal(a):
Mě to přijde jako velice pěkný nápad, můžeš sem dát pro inspiraci svojí implementaci
createComponent
z BasePresenteru? Díky
Předpokládám, že to vypadá nějak takto:
protected function createComponent($name)
{
$callback = array($this, 'create' . ucfirst($name));
if (is_callable($callback)) {
call_user_func($callback, $name)
} else {
// Něco jiného
}
}
- washo
- Člen | 88
Jod napsal(a):
Asi tak nejak by to malo fungovať aj dla mňa. Ja som nato myslel akurát včera, kedže tam robím rovnakú štrúdlu :))) . Ale som si povedal, že ma to tak neobťažuje a aj tak používam napr. na editačný formulár a ten na pridávanie rovnakú metódu s parametrom true/false.
Me to prijde nejake divne… Co to teda umoznuje? Proc pouzivat metodu createComponent($name)? a nevolat rovnou createName1() ?
- Honza Marek
- Člen | 1664
(i když mne ještě trochu obtěžuje ten parametr $name, ale to se ještě dá tolerovat ;).
Dostal jsem takový nápad. Možná by mohly metody
create{ComponentName}
komponentu vracet a ta by se přidala
v metodě createCompoment
pomocí
$this->addComponent($component, $name)
.
- Honza Marek
- Člen | 1664
Takhle to bude asi vůbec nejlepší:
<?php
class BasePresenter extends Presenter
{
/**
* Vytvořit komponentu - zavolá metodu $this->create{Name}
* @param string $name jméno komponenty
*/
protected function createComponent($name)
{
if (String::lower($name) === "component") {
throw new InvalidArgumentException("Argument name '$name' is not allowed.");
}
$callback = array($this, "create" . $name);
if (is_callable($callback)) {
$component = call_user_func($callback, $name);
if ($component instanceof IComponent && $component->getParent() === NULL) {
$this->addComponent($component, $name);
}
} else {
parent::createComponent($name);
}
}
}
?>
Komponenta se může připojit buď:
- v metodě
create{ComponentName}
. Dostane k dispozici parametrem název komponenty. - může být vrácena a pokud nemá rodiče, tak se automaticky připojí
k presenteru v metodě
createComponent
.
Editoval Honza M. (3. 4. 2009 14:38)
- jasir
- Člen | 746
washo napsal(a):
Jod napsal(a):
Asi tak nejak by to malo fungovať aj dla mňa. Ja som nato myslel akurát včera, kedže tam robím rovnakú štrúdlu :))) . Ale som si povedal, že ma to tak neobťažuje a aj tak používam napr. na editačný formulár a ten na pridávanie rovnakú metódu s parametrom true/false.
Me to prijde nejake divne… Co to teda umoznuje? Proc pouzivat metodu createComponent($name)? a nevolat rovnou createName1() ?
Stále to funguje na podobném
principu jako továrnička, čili komponenty si bereš lazy pomocí
$this->getComponent('jmenokomponenty')
(bez předchozího
explicitního volání createName1()
)
Editoval jasir (3. 4. 2009 14:08)
- jasir
- Člen | 746
Honza M. napsal(a):
Komponenta se může připojit buď:
- v metodě
create{ComponentName}
. Dostane k dispozici parametrem název komponenty.- může být vrácena a pokud nemá rodiče, tak se automaticky připojí k presenteru v metodě
createComponent
Jojo, takhle mi to přijde velice pěkné. Dovolil jsem si tam přidat
a zase odstranit :Pucfirst()
Editoval jasir (3. 4. 2009 14:42)
- LM
- Člen | 206
Honza M. napsal(a):
Takhle to bude asi vůbec nejlepší:
<?php class BasePresenter extends Presenter { /** * Vytvořit komponentu - zavolá metodu $this->create{Name} * @param string $name jméno komponenty */ protected function createComponent($name) { $callback = array($this, "create" . $name); if (is_callable($callback)) { $component = call_user_func($callback, $name); if ($component instanceof IComponent && $component->getParent() === NULL) { $this->addComponent($component, $name); } } else { parent::createComponent($name); } } } ?>
Komponenta se může připojit buď:
- v metodě
create{ComponentName}
. Dostane k dispozici parametrem název komponenty.- může být vrácena a pokud nemá rodiče, tak se automaticky připojí k presenteru v metodě
createComponent
Co když si zavolám
$component->getComponent('component')
?
- Honza Marek
- Člen | 1664
jasir napsal(a):
Jojo, takhle mi to přijde velice pěkné. Dovolil jsem si tam přidatucfirst()
To není potřeba, protože php není case sensitive.
- jasir
- Člen | 746
Honza M. napsal(a):
jasir napsal(a):
Jojo, takhle mi to přijde velice pěkné. Dovolil jsem si tam přidatucfirst()
To není potřeba, protože php není case sensitive.
Máš pravdu, nějak jsem žil v domění, že názvy metod jsou case sensitive, stejně jako jména proměnných (která jsou case sensitive). To PHP je ale schizofrení :)
Editoval jasir (3. 4. 2009 14:26)
- Honza Marek
- Člen | 1664
stejně jako jména proměnných (která jsou case sensitive)
Hm… to jsem zase nevěděl já :-D
- Honza Marek
- Člen | 1664
Ee tohle skončí nekonečným cyklem (
createComponent
volá sama sebe).
Jo, už jsem ten dotaz pochopil. Prostě to musíš buď speciálně ošetřit nebo nepoužívat název komponenty „component“.
Přidám tam vyhození výjimky.
Editoval Honza M. (3. 4. 2009 14:32)
- Jan Tvrdík
- Nette guru | 2595
Pokud to dobře chápu, tak už ani není třeba předávat metodě
create{$name}
parametr $name
.
- Honza Marek
- Člen | 1664
Jan Tvrdík napsal(a):
Pokud to dobře chápu, tak už ani není třeba předávat metodě
create{$name}
parametr$name
.
Jj, je to tam jen kvůli případné zpětné kompatibilitě se starými funkcemi.
- RaR
- Člen | 42
Pokud zavolám $component->getComponent('cosi')
, výše
popsaná funkce protected function createComponent($name)
v basePresenteru
bude hledat protected function createCosi($name)
kde v $name bude
zase ‚cosi‘.
Je to tak?
Pokud mám definovaný jeden formulář
$form = new AppForm($this, $name);
a na základě jeho jména se
rozhoduji, co se s daty má dělat, tak toho výše uvedeným způsobem
nedosáhnu, protože když zavolám
$component->getComponent('Form')
, budou se všechny formuláře
jmenovat ‚form‘.
Abych formům mohl přiřadit jméno musím přidat další parametr.
- Honza Marek
- Člen | 1664
RaR napsal(a):
když zavolám$component->getComponent('Form')
, budou se všechny formuláře jmenovat ‚form‘.
Tak v tom případě dostaneš vždycky jeden a ten samý formulář. Pokud
již nebude vytvořen (tedy při prvním volání), tak ho vytvoří (a buď
vrátí nebo sama připojí – podle implementace) metoda
createForm
.
- Jan Tvrdík
- Nette guru | 2595
Honza M. napsal(a): Takhle to bude asi vůbec nejlepší
Tak to už nějakou dobu používám a dnes jsem narazil na dost hustou
chybu. Jedná se o nesmyslné použití funkce is_callable
, která
vždycky vrátí TRUE
, protože Presenter
dědí od
Object
, který definuje metodu __call
a v případě,
že je definována metoda __call
, tak funkce
is_callable
vrací vždy TRUE
(viz komentář na php.net).
Tzn., že funkci is_callable
je nutné nahradit funkcí
method_exists
:)