Rozšíření repository z extension o nové metody

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

Mám repository v modulu. Abych byl konkrétní (s tím se líp pracuje): Mám UserModule, v něm UsersRepository. Pro konkrétní projekt bych potřeboval aby ten modul měl další metody. Ideálně tak, abych jen přidal třídu a ono to samo fungovalo. Představoval bych si to nějak takhle:

class UsersRepository implements IUsersRepository {
	// magic
}

class CustomUsersRepository extends UsersRepository implements IUsersRepository {
	public function customMethod(){
		// magic
	};
}

Napadlo mě přidat to do services a v extension si jen zjistit, jestli už inmterface IUsersRepository má nějakou implementaci, pokud ne → přidat službu UsersRepository. Pokud má implementaci tak nedělat nic.

Pak mě ještě napadlo v extension si vytáhnout všechny implementace interface a pokud existuje nějaká, která dědí tu hlavní, tak ji zaregistrovat, pokud neexistuje tak zaregistrovat tu původní. Tohle se cachuje, takže se to provede jen jednou, že?

Nebo to jde i nějak jinak? Elegantněji?

CZechBoY
Člen | 3608
+
0
-

Ceho se vlastne snazis dosahnout? Kdyz vis ze tu metodu potrebujes tak ji tam dej, ne?
Ja jsem tedka delal pretizeni metody pomoci kompozice (proxy vzor) – potreboval jsem pro urcitou tridu trosku jiny data nez dava vychozi implementace repozitare.

Oli
Člen | 1215
+
0
-

Nemuzji tam dat, protože ten modul mam v composeru a je spolecnej pro všechny projekty. Entity jsem vyřešil traitou, tam to asi jinak nejde. Tady bych vlastně taky mohl, ale pak by aspoň dummy traita musela byt ve všech projektech, to taky nechci. Prave ta traita pro entitu obsahuje další property a v repoditory s tím potřebuju pracovat…

Rozšířit stávající metodu taky není cesta. Bych tam mel zbytečný metody…

CZechBoY
Člen | 3608
+
0
-

No a nemuzes ten repozitar proste podedit a injectovat ten podedenej?

Oli
Člen | 1215
+
0
-

To prave nemuzu. Celej CMS pracuje s puvodni verzi. Musim pracovat s interface a ten musi mit jen jednu implementaci. Ono to co jsem popsal v tý druhý myšlence by vlastně pro mě bylo good enought, pokud, jak předpokládám, se kompilace extension provede jen jednou a pak se bere z cache…

Ale chtěl jsem jen vědět, jestli není nějaká lepší možnost jak to registrovat jako službu.

CZechBoY
Člen | 3608
+
0
-

A proc teda nemuzes podedit tu starou tridu a autowirovat ji? Tu starou proste nebudes pouzivat (nedas do konfigu/vypnes autowire).

Oli
Člen | 1215
+
0
-

Ta stará (base, základní, …) se používá všude v základním CMS. Pokud není potřeba nic sciálního, tak je jediná. Pokud je potřeba speciální metoda, tak potřebuju použít jinou třídu, která rozšiřuje tu základní třídu. A ideálem je detekovat, že existuje rozšiřující třída a registrovat ji. Jinak použít základní.

Prostě chci jen vložit třídu a aby to „magicky“ fungovalo.

  1. Traita v projektu rozšiřuje základní repository: na rozšíření ideální. Bohužel není možný udělat něco jako if trait exists (nebo jo? Takže traita by musela být ve všech projektech.
  2. Načtení všech tříd, který implementují konkrétní interface. Pokud je jen jedna registrovat jako službu. Pokud jich je víc zjistit jestli je jedna základní a druhá ji rozšiřuje (registrovat tu, která rozšiřuje). Pokud něco jiného vyhodit výjimku…

Ta druhá možnost se mě asi líbí, jak tak nad tím diskutujeme/přemýšlím, asi to je cesta kterou se dát. Má to nějaký nevýhody, zádrhely? Je lepší řešení? Nebo tě vubec nechápu? :-)

CZechBoY
Člen | 3608
+
0
-

To CMS má taky nějakej konfigurák, ne? Nebo všechny služby přidáváš přes extension?

  1. ta traita se dá nějak změnit/rozšířit nebo jak to řeší problém?
  2. jj něco takovýho
Oli
Člen | 1215
+
0
-

Má config, ale řeší se tam věci typu název aplikace, email, jazyky, root složka pro obrázky, … Všechny služby si registruje modul, který je za ně zodpovědný tak aby mohl fungovat samostatně.

  1. tu traitu jsem myslel, že bych vložil do UsersRepository. Do toho rodiče. Šlo by to i naopak. Ale neřeší to to, že musím mít ve všech projektech traitu/třídu.
CZechBoY
Člen | 3608
+
0
-

Ta traita ale neřeší nic, ne? Stejně bys musel změnit knihovnu + přidat nějakou traitu, kterou si bude už každej měnit sám (tzn. nebude v knihovně).

Proč vlastně tu metodu potřebuješ mít v tom repozitáři? Nejde si v té třídě využivající daný repozitář vyžádat ještě další třídu, která by měla je tu jednu přídavnou metodu?

Oli
Člen | 1215
+
0
-

Ta traita by byla v projektu. A repositar by mel natvrdo use TUserRepository. Proto by ta traita musela byt ve vsech projektech.

Proč vlastně tu metodu potřebuješ mít v tom repozitáři? Nejde si v té třídě využivající daný repozitář vyžádat ještě další třídu, která by měla je tu jednu přídavnou metodu?

Tohle se mě nelíbí, protože mě to zavádí další závislost, která mě přijde zbytečná. A je to víc psaní. Jedinej problém je právě v registraci služby.

Ale teď mě napadlo, nemá být v Nette 2.4 něco jako priorita služeb? Že může být víc implementací interface a já si nastavím, kterou chci využít… Nebo jsem to viděl v nějakým srovnání se Symfony? Už nevím…

Oli
Člen | 1215
+
0
-

Tak jsem si s tím trochu hrál a potřeboval bych poradit.

Jakým způsobem zaregistrovat třídu podle interface?

Chtěl bych si načíst všechny třídy, který implementují konkrétní interface a pak se rozhodnout, kterou třídu registrovat. Zkoušel jsem něco jako

foreach (get_declared_classes() as $className) {
	if (in_array(IUserRepository::class, class_implements($className))) {
		dump( $className);
	}
}

Ale v get_declared_classes() nejsou třídy, který nejsou jako služby. Pokud zase dám víc služeb se stejným interfacem, tak to spadne v Nette, že je moc služeb se stejným interface.

Jde tohle nějak vyřešit?

CZechBoY
Člen | 3608
+
0
-

Tak spadne to v Nette, protože někde autowiruješ podle toho interfacu a Nette neví kterou třídu tam má dát.
Zkus zapnout v té extension autowire jen u jedný třídy danýho rozhraní.