Odkaz na service z includovaného konfiguráku

- uestla
 - Backer | 799
 
Dobrý večer.
Mám dotaz, je-li možné – případně jak – z includovaného konfiguráku přistoupit ke službě definované v konfiguráku nadřaženém?
#config.neon
common:
	includes:
		- include.neon
	service:
		myService: MyServiceService( ... )
#include.neon
parameters:
	callback: [@myService, loadKey]
Předchozí ukázka bohužel při zavolání
$cb = $container->parameters['callback'];
callback($cb[0], $cb[1])->invoke();
zařve, že callback @myService::loadKey() je nevolatelný –
čili @myService se nepřeloží na instanci služby :-(
Předem děkuji.

- Filip Procházka
 - Moderator | 4668
 
A proč bys to dělal? Nepiš mi, jak to potřebuješ udělat, napiš mi proč to potřebuješ udělat a já ti poradím, jak to udělat lépe.

- uestla
 - Backer | 799
 
Tvořím dynamickou navigaci a některé položky je třeba načítat odjinud (z databáze, z jiného konfigu, …).
Základní strukturu menu tahám právě z includovaného configu:
# config.neon --------
common:
	includes:
		- menu.neon
# menu.neon --------
parameters:
	menu:
		':Homepage:default': 'Úvod'
		':Homepage:contact?lang=cs': 'Kontakt'
		':Homepage:contact?lang=en': 'Contact'
		# a teď je tu např. potřeba pro hierarchizaci načíst položky odjinud
		':Gallery:default':
			title: 'Fotogalerie'
			items: '...'	# a zde by se mi hodil callback
					# využívající služby kontejneru,
					# který by natáhl dynamické položky
Při zpracovávání konfigu (iterací položek) si zjišťuji, zda
aktuální položka náhodou není pole (resp. ArrayHash, na který
si to pro ušetření paměti přetypovávám) a neobsahuje 'items'
a když je to callback, tak ho volám pro načtení.
# metoda komponenty MenuControl
private function processItems($parent, ArrayHash $items)
{
	foreach ($items as $dest => $item) {
		if ($item instanceof ArrayHash) {
			$item['parent'] = $parent;
			$item['dest'] = $dest;
			if (isset($item['items'])) {
				$this->processItems($item, $item['items']);
			}
		} else {
			$items[$dest] = ArrayHash::from(array(
				'parent' => $parent,
				'dest' => $dest,
				'text' => $item,
			));
		}
	}
}
Děkuji za ochotu.
EDIT: komentář v NEONu
Editoval uestla (9. 3. 2012 18:35)

- Filip Procházka
 - Moderator | 4668
 
Především, celé tvé menu může být v samostatném souboru, tomu snad nic nebrání, ne?
':Homepage:default': 'Úvod'
':Homepage:contact?lang=cs': 'Kontakt'
':Homepage:contact?lang=en': 'Contact'
# a teď je tu např. potřeba pro hierarchizaci načíst položky odjinud
':Gallery:default':
	title: 'Fotogalerie'
	items: '...'    # a zde by se mi hodil callback využívající služby kontejneru, který by natáhl dynamické položky
Můžeš ho načítat cca takto
$menuItems = Nette\Utils\Neon::decode(file_get_contents($file));
Asi by bylo dobré, si na to vytvořit nějaký pěkný interface
interface MenuItemsProvider
{
	function getMenuItems();
}
Tohle interface si pak implementuješ ve své službě a už tam pak nastavíš pouze jméno služby
':Gallery:default':
	title: 'Fotogalerie'
	items: myCoolService
A trošku upravíš metodu na vytvoření menu
private function processItems($items, $parent = NULL)
{
        foreach ($items as $dest => $item) {
                if ($item instanceof ArrayHash) {
                        $item['parent'] = $parent;
                        $item['dest'] = $dest;
			if (is_string($item['items'])) {
				$provider = $this->container->getService($item['items']);
				$item['items'] = $provider->getMenuItems();
			}
                        if (isset($item['items'])) {
                                $this->processItems($item['items'], $item);
                        }
                } else {
                        $items[$dest] = ArrayHash::from(array(
                                'parent' => $parent,
                                'dest' => $dest,
                                'text' => $item,
                        ));
                }
        }
}
Příklad pracuje s Containerem, který tam musíš přidat. Pokud to chceš mít ale ještě čistější, tak si můžeš všem službám, které budou implementovat ten interface, přidat tag
services:
	galleries:
		class: Galleries(@db)
		tags: {menuProvider: gallery}
Potom si je z containeru získáš (ideálně v compileru) a nastavíš je, aby se předávaly té komponentě na menu, do jednoho setteru
public function addProvider($name, $service)
{
	$this->providers[$name] = $service;
}
Takto si nebudeš muset předávat celý container (čistější) a budeš tam mít rovnou služby, které budeš potřebovat.
Editoval HosipLan (9. 3. 2012 20:01)

- uestla
 - Backer | 799
 
Děkuji moc za nástřel. Nakonec jsem na to šel trochu přímočařeji, tak se podělím:
https://gist.github.com/2008990
Ještě jednou díky.