DI kontajner a lazy loading
- ricco24
- Člen | 141
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
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 :) ):
- Filip Procházka
- Moderator | 4668
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
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
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
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
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
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.
- David Grudl
- Nette Core | 8227
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
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).