Jak odstranit Environment::getCache(„foo“) z kódu

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

Ahoj,

právě předělávám firemní systém a jelikož chci jít s dobou, snažím se minimalizovat výskyt volání Environment.

Implementoval jsem si upravený DI podle Honzi Marka, ale co nevím jakým způsobem nahradit je získání cache – Environment::getCache("foo"). Má to vůbec smysl? Filestorage se dá nahradit pomocí konfigu, takže při testování by problém taky být neměl, nebo se pletu?

Filip Procházka
Moderator | 4668
+
0
-

Ahoj, právě jsem dokončil (snad) refaktoring Patrikového DI a mělo by to fungovat ok. Mám to trochu více rozdělené a připojuji to do systému pomocí vlastního konfigurátoru

Když si prohlédneš https://github.com/…actories.php tak třeba i pochopíš jak se to používá a jak jdou určité věci spojovat a nahrazovat :)

norbe
Backer | 405
+
0
-

Ono se to co do použití moc neliší od toho co má Honza, naopak mi přijde lepší jeho konfigurace skrz konfigurák. Co jsem ale nepochopil ani z těch tvých zdrojáků je jak nahradit zmiňovaný kód Environment::getCache("foo"). To bych měl pro každý namespace keše vytvářet novou konfiguraci, kde akorát změním parametr konstruktoru? To mi nepřijde jako nejlepší řešení… Proto se zeptám ještě jednou:

Má to vůbec smysl? Filestorage si můžu nastavit v konfigu. Co je tedy špatného na použití Environment::getCache(„foo“)? Jaké konkrétní problémy mi to může způsobit?

Jan Tvrdík
Nette guru | 2595
+
0
-

Čisté řešení (dle mě) pro náhradu Environment::getCache("foo") v presenteru je doplnit do BasePresenteru:

public function getCache($namespace)
{
	return new Nette\Caching\Cache($this->getCacheStorage(), $namespace);
}

public function getCacheStorage()
{
	return $this->getContext()->getService('Nette\\Caching\\ICacheStorage');
}

Jaké konkrétní problémy mi to může způsobit?

Nahrazování cache storage bude škaredé (tj. úpravou kontextu Env. místo úpravou kontextu presenteru).

Filip Procházka
Moderator | 4668
+
0
-

Ale samozřejmě, že to jde nastavit v configu… Tohle jsou jenom rozepsané a více nakonfigurované výchozí služby a ukazují možnosti konfigurace.

Funguje to tak, že se

  • vymění výchozí Configurator za nový
  • v momentě načtení configu (Environment::loadConfig()) se automaticky vytváří ServiceContainer
  • tento ServiceContainer je naplněn hodnotami z Configu a zároveň jsou mu upraveny služby, aby odpovídaly nastavení z configu
  • služby, které se mají spustit hned (run: TRUE) tak se spustí a ServiceContainer nyní obsahuje všechny služby a všechny data z Configu (odpadá potřeba volat Environmeng::getVariable())

Do jakékoliv služby předám tak přesně co potřebuji včetně jiných libovolných zaregistrovaných služeb, což mi docela zásadně rozšiřuje možnosti jak „surové konfigurace“ pomocí nastavení jako je třeba to memcache v odkazu, tak i možnosti parametrů předané továrničce. Viz vytváření EntityManageru.

Navíc moje implementace má pár vychytávek navíc.

  • Pokud služba implementuje IContainerAware je jí ServiceContainer předán automaticky.
  • Je možné nadefinovat alias (aliases: ['memcache']) a pak k té službě přes něj přistupovat, třeba v presenteru $this->getServiceContainer()->memcache, $this->getServiceContainer()->httpRequest, …
  • Patrikova implementace dovoluje ke službám (a aliasům) přistupovat přes ArrayAccess, já se rozhodl, že přes ArrayAcces budou přístupné (stejně jako přes ServiceContainer::getParameter($key)) konfigurační direktivy. Lze proto volat $this->serviceContainer['database']; // database z configu.
  • V konfiguraci argumentů továrniček, tříd a metod mám navic syntaktickou třešničku a je možné předávat rovnou prvky pole array('%database[host]%', '%database[username]%', '%database[password]%'), počítá se ale pouze s jedním zanořením (%neco[neco][neco]% vyhodi chybu)

Editoval HosipLan (17. 3. 2011 21:39)

Jan Tvrdík
Nette guru | 2595
+
0
-

Zdá se mi to, nebo jsi pořád neodpověděl na otázku, jak nahradit Environment::getCache("foo")? :o)

Filip Procházka
Moderator | 4668
+
0
-

Máš pravdu neodpověděl jsem přímo, jenom jsem ukázal jaké jsou možnosti :)

Co třeba nastavit službu, aby přijímala ICacheStorage?

nastavení

service:
	MySuperService:
		class: MySuperService
		arguments: ['@Nette\Caching\ICacheStorage']

služba

class MySuperService extends Nette\Object
{
	/** @var Nette\Caching\Cache */
	private $cache;

	public function __construct(Nette\Caching\ICacheStorage $storage)
	{
		$this->cache = new Nette\Caching\Cache($storage, __CLASS__);
	}

	// ...
}

v případě presenteru je to velice podobné, tam by se dal i udělat helper, který by jako v environment vracel vždy jinou instanci třídy Nette\Caching\Cache podle argumentu.

Editoval HosipLan (17. 3. 2011 21:41)

Jan Tvrdík
Nette guru | 2595
+
0
-

Díky za praktickou ukázku, vypadá to pěkně. Těším se, až se něco takového dostane do Nette.

Patrik Votoček
Člen | 2221
+
0
-

Jan Tvrdík napsal(a):

Čisté řešení (dle mě) pro náhradu Environment::getCache("foo") v presenteru je doplnit do BasePresenteru:

public function getCache($namespace)
{
	return new Nette\Caching\Cache($this->getCacheStorage(), $namespace);
}

public function getCacheStorage()
{
	return $this->getContext()->getService('Nette\\Caching\\ICacheStorage');
}

Posledních pár dní pracuju s cache pomocí DI a začalo mě extrémně vadit že Nette\Caching\Cache nemá setter pro nastavení namespace. A tak jsem se nad tím zamyslel hlouběji a zkoumal jsem jak na to až jsem došel k tomu že lepší řešení než to co jsi napsal nevymyslím (došel jsem ke stejnému).

Takže ve výsledku je odpověď taková že se injektuje Storage a instancuje se „ručně“.

norbe
Backer | 405
+
0
-

Díky za tipy, hnedka to vypadá líp než nastavovat speciální službu pro každé použití cache. Po pravdě jsem se k obdobnému řešení dopracoval i po zkouknutí pár tříd v nette, ale přišlo mi to trochu proti principu DI vytvářet na pevno instanci nějaké třídy. Asi to bude chtít trochu citu, co ještě posílat konstruktorem/setterem a co už vytvářet na pevno v dané třídě.

Patrik Votoček
Člen | 2221
+
0
-

Tak teoreticky by šlo udělat i:

class MyCache extends \Nette\Caching\Cache
{
	public function getCacheNamespace($namespace = NULL)
	{
		return new self($this->getStorage(), $namespace);
	}
}

a jako službu používat MyCache místo Nette\Caching\Cache.

Jan Tvrdík
Nette guru | 2595
+
0
-

norbe wrote:

přišlo mi to trochu proti principu DI vytvářet na pevno instanci nějaké třídy

Ty používáš DI jen ze srandy nebo aby si byl cool? Já používám DI, aby se kód snáze testoval, a to mnou navržené řešení bez problému splňuje. Nedává smysl používat DI jen tak pro nic za nic.

Co ještě posílat konstruktorem/setterem a co už vytvářet na pevno v dané třídě.

Nechápu, musel bys mi poslat ukázku.


Patrik Votoček wrote: Tak teoreticky by šlo udělat i (…)

To se mi nelíbí.


OT: Nechce někdo Davidovi poslat úpravu stylu pro citace? Ty současné jsou strašně nafouklé.

norbe
Backer | 405
+
0
-

No rozhodně to nedělám jen abych si zkrátil dlouhou chvíli, ale právě proto, že mně čeká poměrně dost úprav, tak chci aby to bylo udělané pořádně. Mimo jiné taky konečně začínám s psaním testů a proto si potřebuju ujasnit nějaké základní principy.

Nechápu, musel bys mi poslat ukázku.

To právě souviselo s tím příkladem s cachí. Jakože si člověk musí získat trochu citu pro to, co mu tam při testech může dělat problém, což se mně jako někomu kdo s tím teprve začíná určuje blbě.

Editoval norbe (18. 3. 2011 10:59)

Jan Tvrdík
Nette guru | 2595
+
0
-

Tak v testech jde o to nahradit závislosti a toho konkrétně v případě presenteru můžeš dosáhnout dvěma způsoby (bez toho, abys to složitě mockoval):

  1. předáš mu upravený kontext (DI princip)
  2. vytvoříš si potomka, který překryje třeba právě tu metodu getCache.
Filip Procházka
Moderator | 4668
+
0
-
  1. A u služby, která nevyžaduje celý Context jí předáš jenom ICacheStorage :)

Editoval HosipLan (18. 3. 2011 11:29)

knyttl
Člen | 196
+
0
-

Jak by se tohle dnes řešilo se současně implementovaným DI?

Filip Procházka
Moderator | 4668
+
0
-

přesně takhle https://forum.nette.org/…e-foo-z-kodu#…, jenom to nebude @Nette\Caching\ICacheStorage ale @cacheStorage

Editoval HosipLan (20. 5. 2011 11:05)