DI kontajner a lazy loading

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

Dá sa pomocou config.neon vytvoriť DI kontajner ktorý by obsluhoval nasledovný lazy loading ?

Dajme tomu že máme objekt Article. V objekte Article môže byť metóda ktorá pre svoju činnosť využíva db pripojenie (save) ale aj metóda ktorá db pripojenie nepotrebuje (showActual – napríklad práve písaný naformátovaný článok). Chcel by som do triedy Article predávať objekt ktorý by mi db pripojenie vytvoril len v prípade že by to objekt Article skutočne potreboval.

Pri takejto definícii v config.neon sa mi pri vytváraní instancie Article automaticky vytvorí aj db pripojenie

service:
	database:
		class: Nette\Database\Connection
		arguments: ...

	article:
		class: Article (@database)

Napadá ma napríklad predať do Article celý systémový kontajner a trieda by si db pripojenie vytvorila len vtedy kedy to bude potrebovať no tým by bolo porušené DI.
Iná možnosť je vytvoriť Accessor na databázu no tomu by opäť bolo potrebné predávať celý systémový kontajner aby v momente požiadavky mohol vytvoriť db pripojenie.

Je dosť možné že som niečo prehliadol … ako by sa to dalo vyriešiť ?

sláva
Člen | 4
+
0
-

David Grudl o tomto tématu nedávno psal na svém blogu (nicméně ho někteří v následné diskusi chtěli sežrat zaživa, pokud si dobře pamatuju :) ):

https://phpfashion.com/…lazy-loading

ricco24
Člen | 141
+
0
-

Ano tento článok som si prečítal no ide mi priamo o implementáciu pomocou DI kontajneru v nette.

Dá sa v config.neon vytvoriť služba ktorej budem predávať ako parameter inú službu v podobe callbacku ? Tým by sa dal implementovať CallbackAccessor ktorý Dávid uvádza v článku.

Filip Procházka
Moderator | 4668
+
0
-

Teď na to není syntax sugar. Ale pokud na tom trváš

class ServiceAccessor extends Nette\Object
{
	private $serviceName;
	private $container;

	public function __construct($serviceName, Nette\DI\Container $container)
	{
		$this->serviceName = $serviceName;
		$this->container = $container;
	}

	public function get()
	{
		return $this->container->{$this->serviceName};
	}
}
service:
        article:
                class: Article(ServiceAccessor(database))

Do article se předá třída ServiceAccessor, které bude předán název služby „database“ a taky automaticky pomocí autowire (magie) DI Container.

Article by pak mohl vypadat takto

class Article extends Nette\Object
{
	private $database;

	public function __construct(ServiceAccessor $database)
	{
		$this->database = $database;
	}

	public function save()
	{
		$articles = $this->database->get()->table('articles');
		// ...
	}
}

Editoval HosipLan (19. 4. 2012 8:36)

ricco24
Člen | 141
+
0
-

Ako riešenie ma to taktiež napadlo no ako som písal v prvom poste musíš ServiceAccessoru predávať celý DI kontajner čo mi moc ako DI nepríde keďže pri jednotlivých službách nepotrebuješ dostávať celý „klavír“.

Neplánuje sa pridať možnosť predávať ako parameter služby aj callback ? Niečo na spôsob

service:
	article:
		class: Article(ServiceAccessor(callback:@database))
class ServiceAccessor extends Nette\Object
{
	public $callback;
	public $servce;

 	public function __construct($callback) {
		$this->callback = $callback;
	}

	public function get() {
		if(!$this->service) {
			$this->service = call_user_func($this->callback);
		}

		return $this->service;
	}
}

a article podobne ako u teba

class Article extends Nette\Object
{
	private $databaseAccessor;

	public function __construct(ServiceAccessor $databaseAccessor) {
		$this->databaseAccessor = $databaseAccessor;
	}

	public function save() {
		$database = $this->databaseAccessor->get();

		$database->... save
	}
}

//EDIT:
Hmm ako som to dopísal ma napadlo že pri takomto predávaní callbacku by asi nebolo možné ustriehnuť počet instancií služby v DI kontajnery …

Editoval ricco24 (19. 4. 2012 9:17)

Filip Procházka
Moderator | 4668
+
0
-

Vůbec sis nepomohl, moje řešení je daleko lepší. Nepředáváš totiž své službě Container, ona o něm vůbec neví, dostane jen Accessor.

ricco24
Člen | 141
+
0
-

Ano trieda Article nedostane Container ale iba Accessor no pri jej vytváraní predáš triede Accessor celý kontajner ktorý nepotrebuje pretože vždy bude obsluhovať prístup len k jednej službe. Preto som chcel triede Accessor predávať len to čo potrebuje.

Ale ok, nechám si poradiť od skúsenejších :-)

Filip Procházka
Moderator | 4668
+
0
-

To ale nedává smysl. Musel by jsi instanci accessoru vytvářet takto

$container->addService('connectionAccessor', new ServiceAccessor(function () use ($container) {
	return $container->connection;
}));

A to do Neonu nezapíšeš, musela by pro to být podpora přímo v Nette.

David Grudl
Nette Core | 8227
+
0
-

HosipLan napsal(a):

Vůbec sis nepomohl, moje řešení je daleko lepší. Nepředáváš totiž své službě Container, ona o něm vůbec neví, dostane jen Accessor.

Ale ví. Není možné vytvořit třídu Article bez Containeru. Správné řešení je použít interface.

Filip Procházka
Moderator | 4668
+
0
-

To máš samozřejmě pravdu, ale nechtěl jsem to komplikovat :)

David Grudl
Nette Core | 8227
+
0
-

Zjednodušování je v pořádku, pokud však nedělá ze správného řešení řešení chybné.

Honza Marek
Člen | 1664
+
0
-

Je pravděpodobné, že v aplikaci dojde ke stavu, že vůbec na nic není potřeba databázové spojení? Pokud ne, tak se lazy loadingem nic neušetří, protože předání již hotového objektu je zadarmo (i o maličko levnější než vytvoření nějakého accessoru).

David Grudl
Nette Core | 8227
+
0
-

Aneb předčasná optimalizace.