Přidávání subkomponenty k více komponentám

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

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)

mkoubik
Člen | 728
+
0
-

Komponenty neregistruj přímo jako služby, vytvoř si na ně továrničky.

Michal Schneider
Člen | 13
+
0
-

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
+
0
-

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 :)

Michal Schneider
Člen | 13
+
0
-

Dík moc za vyčerpávající vysvětlení. Už tomu začínám rozumět ;-)

mkoubik
Člen | 728
+
0
-

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
+
0
-

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())
Michal Schneider
Člen | 13
+
0
-

Díky moc! Tohle mi opravdu pomohlo!