Odkaz na service z includovaného konfiguráku

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
uestla
Backer | 799
+
0
-

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

Pochopitelně, v parametrech nemají služby co dělat.

uestla
Backer | 799
+
0
-

A existuje nějaký způsob, jak docílit požadovaného? Čili výsledek nějaké metody služby zaznamenat do parametru kontajnéru?

Napadá mne jen nějak využít setup u samotného kontajnéru, ale nepřijde mi to moc košér :-(

Filip Procházka
Moderator | 4668
+
0
-

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

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)

awsickness
Člen | 98
+
0
-

tak te komponente predavej parameters: menu a pak rovnou generuj menu.

Filip Procházka
Moderator | 4668
+
0
-

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

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.