vytvoření komponenty v nette 2.1. bez presenteru
- Filip111
- Člen | 244
Ahoj, snažím se aktualizovat na nette 2.1 a po po pár hodinách mam dojem, že to můžu všechno zahodit. Přečetl jsem https://doc.nette.org/…tion/factory, koukal na přednášku https://www.youtube.com/watch?… ale stejně v tom plavu.
Asi chápu jak vytvořit komponentu z presenteru – vytvořim si továrnu,
jako službu injectuji do presenteru a v metodě createComponentKomponenta
zavolám create nad factory.
Co jsem ale nepochopil, jak definovat komponentu v neonu.
Hodně jsem používal komponenty jen v šablone
{control supervisorClient}
s tím, že továrnička byla jen
v konfigu:
supervisorClient:
class: web123\Components\SupervisorClient
Presenter tedy o nějaké komponentě vůbec nevěděl, což bylo supr,
protože jsem u každého zákazníka mohl upravovat libovolně šablony,
konfig ale presenter zůstal beze změny.
Jak toho docílit v Nette 2.1 ?
Napsal jsem si generovanou factory i ručně napsanou, ale stále dostávám chybu, že komponenta neexistuje.
supervisorClient:
implement: web123\Components\ISupervisorClientFactory
namespace web123\Components;
interface ISupervisorClientFactory
{
/** @return SupervisorClient */
function create();
}
Jde to použít i bez presenteru aniž bych definoval někde createControlSupervisorClient ?
Jaký je nejsnazší způsob migrace továrniček z 2.0 do 2.1 ? Musím opravdu napsat desítky interfaců pro factory nebo existuje něco snašího?
Díky.
- Šaman
- Člen | 2668
Továrničky potřebovaly interface vždycky. Jestli jsi ho nepoužíval, tak
jsi tu komponenty definoval jako služby, což lze stále. Jediné, co se
změnilo, je sdružení sekcí factories
a services
do
jedné, už jsou pouze services
.
Můžeš si napsat do BasePresenteru supertovárnu
createComponent($name)
, která ti vrátí instanci správné
komponenty. Může si ji vytáhnou z kontejneru jako službu, může ji
v nejhorším i sama vytvořit. Ale rozhodně to není čisté a už vůbec ne
best practise!
P.S. Sorry, první odstavec možná popisuje vývojovou verzi před vydáním 2.1. Ale druhý platí, jen je to na úkor čitelnosti a bezpečnosti (každý presenter může vytvořit jakoukoliv komponentu a nemáš nad tím kontrolu).
- Filip111
- Člen | 244
Teď jsem možná trochu mystifikoval – mě to „bez“ presenteru fungovalo, protože už dávno supertovárničku používám:
protected function createComponent($name) {
if (method_exists($this->getContext(), $method = 'create' . ucfirst($name))) {
$component = $this->getContext()->$method($name);
return $component;
}
return parent::createComponent($name);
}
Presenter tedy obejít nelze? Vždy musí existovat metoda createControlXXX a
nové Factory třídy nebo iterfacy
jen usnadňují napsání createControlXXX metody v presenteru?
(začínám si myslet, že ne – ale tak jsem si na to zvykl, že jsem to považoval za Nette feature)
- Šaman
- Člen | 2668
Komponentu musíš vytvořit v kontejneru (ve smyslu komponenta schopná
obsahovat jiné komponenty, neplést s aplikačním DI kontejnerem). Kontejnery
jsou presentery a všechny komponenty (extends Control).
Každá komponenta vzniká v továrničče obecné
createComponent($name)
, nebo konkrétní
createComponentName()
. Tak tomu bylo už od 0.9 a je tomu
stále.
Factories a interfacy se netýkají primárně komponent, je to nástroj, jak
z DI kontejneru dostat buď stále stejnou instanci (services), nebo pokaždé
novou instanci třídy (staré factories, dnes services pomocí interface). Ale
to, že se dá komponenta vykreslit v šabloně pomocí makra
{control name}
je jen díky továrničce, která v presenteru,
nebo nadřízené komponentě musí (a vždy musela) být.
- David Grudl
- Nette Core | 8282
Rozdíl mezi 2.0 a 2.1 je v tom, že ty metody nemají prefix
create
, ale createService
. Lepší je použít
přímo metodu createService
:
if ($this->getContext()->hasService($name)) {
$component = $this->getContext()->createService($name);
return $component;
}
Ale používání getContext() není best practice. A vidím v tom i bezpečnostní riziko, protože změnou v URL mohu tahat libovolné služby.
- Filip111
- Člen | 244
Díky, začínám se tím prokousávat – na createService jsem přišel,
když jsem si prošel vygenerovaný SystemContainer.
Nikdy jsem neuvažoval o tom, že změnou url můžu vlastně zavolat jinou
komponentu nebo teď dokonce i službu. Asi by se dalo vymyslet, jak toho
zneužít.
Každopádně jsem přišel na způsob, jak to rozběhnout bez velkých změn – tedy stačí zakomentovat v konfigu sekci factories: a přesunout ji do services + následující supertovárnička:
protected function createComponent($name) {
if ($this->getContext()->hasService($name)) {
$component = $this->getContext()->createService($name);
if (method_exists($component, 'create'))
// vytvarim komponentu pomoci Factory nebo IFactory
return $component->create();
else
// vracim komponentu puvodne definovanou v konfigu v sekci factories:
return clone $component;
}
// hledam tovarnicku createComponentName v presenteru
return parent::createComponent($name);
}
Tohle „funguje“, bezpochyby je to prasárna.
No jdu psát interfacy pro factory, abych to klonování služeb smazal dřív
než si ho všimnete :)
- David Grudl
- Nette Core | 8282
V takovém případě ale interface nijak nevyužíváš, naopak ti
překážení. Takže je pak lepší zůstat u způsobu definice
class: xxx
místo implement: xxx
.
- Filip111
- Člen | 244
Říkal jsem si, že k některým komponentám dodělám Factory, které pak
správně injectované do presenteru použiji v továrničce
createComponentNazev.
Je ale pravda, že v okamžiku, kdy definuji službu s Factory se mi
komponenta vytvoří pomocí uvedené super továrny, což je blbý –
opuštění konceptu supertovárny ve stávajících projektech je skoro
nemožný.
- David Matějka
- Moderator | 6445
@Filip111: tak to udelej obracene, nejdriv zkus createComponent* a az pak pouzij supertovarnu..
protected function createComponent($name) {
$component = parent::createComponent($name);
if($component) {
return $component;
}
...supertovarna
}
- Filip111
- Člen | 244
@matej21:
To by šlo a funguje to dobře – zkoušel jsem inject služby továrny do
presenteru a klasický createComponentNazev.
Staré projekty a komponenty v nich se tedy vytvářejí přes supertovárnu,
nové můžu již dělat klasicky jak se má. Akorát dokud tam bude
supertovárna, bude existovat riziko zneužití.
- David Matějka
- Moderator | 6445
jo, tenhle pristup neni z hlediska bezpecnosti idealni. mohl by sis udelat nejaky whitelist, s komponentami, ktere je mozno vytvorit supertovarnou