Přidávání subkomponenty k více komponentám
- Michal Schneider
- Člen | 13
Ahoj,
chtěl bych poprosit o radu. Mám komponenty typu „mapa“, do které
přidávám subkomponenty jako např. „zoom control“, „scale control“
apod. Konfiguraci komponent typu mapa i subkomponent provádím
v configu takto:
mapaA:
class: Mapa
setup:
- addControl(@zoom)
- addControl(@scale)
mapaB:
class: Mapa
setup:
- addControl(@zoom)
- addControl(@scale)
zoom:
class: Zoom
autowired: no
scale:
class: Scale
autowired: no
V Nette 2.0 toto fungovalo dobře. Bohužel při přechodu na Nette 2.1 dojde k chybovému hlášení Component ‚zoom‘ already has a parent. To je způsobené tím, že přidání komponenty ve vygenerovaném SystemContaineru se děje pomocí funkce getService, která očividně volá již jednou vytvořenou komponentu zoom.
Nevěděli byste prosím, jak toto vyřešit? Bez toho, abych v configu musel mít komponentu zoom 2krát?
Dík moc.
Editoval Michal Schneider (27. 1. 2014 12:52)
- Michal Schneider
- Člen | 13
mkoubik napsal(a):
Komponenty neregistruj přímo jako služby, vytvoř si na ně továrničky.
Díky moc za rychlou reakci. Prostudoval jsem odkaz a udělal jsem to tedy tak, že pro všechny komponenty, které chci přidávat do mapy jsem vytvořil statickou funkci create a výsledný konfigurák bude vypadat takto:
mapaA:
class: Mapa
setup:
- addControl(@zoom::create())
- addControl(@scale::create())
mapaB:
class: Mapa
setup:
- addControl(@zoom::create())
- addControl(@scale::create())
zoom:
class: Zoom
autowired: no
scale:
class: Scale
autowired: no
Není to nic proti ničemu? ;-)
- vvoody
- Člen | 910
Je. V DIC si udržuješ po jednej (úplne nevyužitej) inštancii z každej komponenty (zaregistrovanej ako služby) ktoré slúžia len na to aby si mohol odkázať na statickú metódu triedy z ktorej boli inštancované. Čiže celkom logický nezmysel.
Služba by nemala byť komponenta, kedže tých komponent môžeš potrebovať viac inštancií pri jednom requeste. To je myslím že jasné, takže potrebuješ továreň. Teraz prečo nemôže byť továreň ako statická metóda? Keď chceme predávať továreň ako závislosť, tak by mal byť zaregistrovaná ako služba a služba musí byť inštancovatelná trieda, takže továreň nemôže byt riešená ako statická metóda.
Takže oddeľ tu továreň od komponenty :)
- mkoubik
- Člen | 728
Myslel jsem to nějak takhle:
interface IZoomFactory
{
/** @return Zoom */
public function create();
}
interface IScaleFactory
{
/** @return Scale */
public function create();
}
class MapFactory
{
private $zoomFactory;
private $scaleFactory;
public function __construct(IZoomFactory $zoomFactory, IScaleFactory $scaleFactory)
{
$this->zoomFactory = $zoomFactory;
$this->scaleFactory = $scaleFactory;
}
public function create()
{
$map = new Mapa();
$map->addControl($this->zoomFactory->create());
$map->addControl($this->scaleFactory->create());
return $map;
}
}
services:
zoomFactory:
implement: IZoomFactory
scaleFactory:
implement: IScaleFactory
mapFactory: MapFactory
Pak si injektni MapFactory
a vytvoř si komponentu zavoláním
$mapa = $mapFactory->create()
.
- Jan Tvrdík
- Nette guru | 2595
Dokonce lze auto-implementovat i tu MapFactory =)
interface IMapFactory
{
/** @return Map */
public function create();
}
services:
...
mapFactory:
implement: IMapFactory
setup:
- addControl(@zoomFactory::create())
- addControl(@scaleFactory::create())