Vytváření repository pomocí továrniček

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

Jsem s nette takový pokročilejší začátečník. Jediné co mi na něm vadí je spousta formalismů, které trvá dlouho napsat.

Nevím nakolik to je košér, ale některá repository vyvářím pomocí továrničky a na některá složitější vyvářím složitější třídu dědící od Repository().

class RepositoryFactory {
    public function __construct(\Nette\Database\Connection $db) {
	$this->db = $db;
    }
   public function createRepository($table){
	return new Repository($this->db, $table);
    }
    public function createUser(){
	$rep = $this->createRepository("user");
	$rep->setDemandedKeys("login");
	$rep->setAllowedKeys("login, password, role, name, firstname, lastname, email");
	return $rep;
    }
(

Říkám si ale jestli by nebylo vhodné mít userRepository v di kontejneru jako service, aby se zbytečně nevytvářela nová instance pokaždé, když potřebuji Repository, které jsem už někde použil.

Něco ve smyslu (vím, že je to velká ptákovina):

services:
	repositoryFactory: RepositoryFactory
	userRepository: @repositoryFactory->createUser();
	userService: UserService(@userRepository)

Tímto postupem bych totálně zabil dependency injection. Vytvářet ale třídu kvůli každé funkci uvnitř továrničky mi přijde poněkud zhůvěřilé.

Co si o tomto přístupu myslíte? Jak by bylo nejvhodnější to vyřešit?

Editoval danielseek (16. 11. 2013 10:55)

Šaman
Člen | 2668
+
0
-

Nevím, kde jsi přišel na ten způsob s továrnou, ale já používám (a ve všech příkladech jsem viděl) obyčejnou službu, která se do presenterů dá injectovat i pomocí property injection extrémně jednoduše pomocí anotace.
Navíc v configu nemusí být ani pojmenovaná (pracujeme s rozhraním a závislost UserService na UserRepository pořeší autowiring.)

services:
	- App\Model\UserRepository;
	- App\Model\UserService;
<?php

use App\Model\UserService; # tohle tu ani není potřeba, ale mám rád vyjmenované všechny závislosti v sekci use

class UserPresenter extends BasePResenter
{
	/**
	 * @var App\Model\UserService <-- tady zatím MUSÍ být plný NS
	 * @inject
	 */
	public $users;

	public function renderUserList()
	{
		$this->template->users = $this->users->findAll();
	}
}
?>

Editoval Šaman (16. 11. 2013 13:14)

danielseek
Člen | 42
+
0
-

No jednoduše mě nebaví mít miliardy tříd…

arron
Člen | 464
+
0
-

V té továrně musíš nějak skladovat ty instance a vracet je, když už jsou vytvořené. Takže takový malý kontainer. Funguje to skvěle u repository, kde do každé instance předáváš stejné závislosti, ale začne to selhávat tam, kde každá instance potřebuje nějaké jiné závislosti. Tam už pak musíš definovat ty služby explicitně v configu bez ohledu na to, kolik jich je a že jsou si třeba docela podobné.

danielseek
Člen | 42
+
0
-

arron napsal(a):

V té továrně musíš nějak skladovat ty instance a vracet je, když už jsou vytvořené.

Jj, to mě napadlo. Domníval jsem se ale, že je to porušením návrhového vzoru factory. Takový věci by měl řešit spíš DI kontejner, je to takový hybrid. Ale z utilitářského hlediska je to asi nejrychlejší řešení.

Factory používám u jednodušších tabulek, kde nejsou žádné složitější závislosti a stačí mi obyčejné CRUD operace…

Editoval danielseek (17. 11. 2013 23:11)

danielseek
Člen | 42
+
0
-

Šaman napsal(a):

Ty injecty pomocí anotací jsou zbytečná magie. Domnívám se, že i sám David Grudl říká, že kde je to možné, doporučuje užít injekci v konstruktoru.

Editoval danielseek (17. 11. 2013 23:15)

Šaman
Člen | 2668
+
0
-

danielseek napsal(a):

Šaman napsal(a):

Ty injecty pomocí anotací jsou zbytečná magie. Domnívám se, že i sám David Grudl říká, že kde je to možné, doporučuje užít injekci v konstruktoru.

To rozhodně, teď se bavíme JEN o injectování do presenteru. Tam se dají použít buď magické property injection (viz příklad), nebo magické method injection (metoda injectFooBar).
Ve vlastním modelu a v naprosté většině komponent se doporučuje používat constructor injection (a rozhodně ne public property, porušuje to zapouzdření).

arron
Člen | 464
+
0
-

danielseek wrote:
Jj, to mě napadlo. Domníval jsem se ale, že je to porušením návrhového vzoru factory. Takový věci by měl řešit spíš DI kontejner, je to takový hybrid. Ale z utilitářského hlediska je to asi nejrychlejší řešení.

Porušení návrhového vzoru factory to možná je, na druhou stranu, ta factory stále vrací objekty, což je to, co já od ní chci a fakt mě nezajímá, jak to dělá (proto používám create:-)). Krom toho je t ovelmi jednoduché a přímočaré řešení, takže bych se toho tolik nebál :-) Refaktorovat to na dvě třídy jde vždycky, když se ukáže, že je to fail :-)

Šaman
Člen | 2668
+
0
-

Mě pořád nejde do hlavy celková koncepce… Chápu to tak, že vlastně nemáš skutečné repository? Co od toho repozitáře vlastně očekáváš? Možná by se dalo přijít na jednodušší způsob už na úrovni modelu.

bazo
Člen | 620
+
0
-

danielseek napsal(a):

Jediné co mi na něm vadí je spousta formalismů, které trvá dlouho napsat.

tak to si asi este nevidel symfony2 :) nette absolutne ulahcuje zapisovanie akychkolvek konfiguracii.

ale k problemu, urcite ti doporucujem si vytvorit pre kazdu repository zvlast triedu a zaregistrovat si kazdu zvlast ako service. repository potom mozu obsahovat vsetky mozne query ktore potrebujes

danielseek
Člen | 42
+
0
-

bazo napsal(a):
tak to si asi este nevidel symfony2 :)

To je pravda :)

Jde o to, že od devadesáti procent repository nevyžaduji nic náročnějšího než CRUD operace, o zbytek se mi buďto stará servisní třída, nebo to prasím přímo do presenteru, když to není náročná aplikace. Jediné v čem se v praxi liší jsou sloupce v db.

Dělám ještě jednu takovou další prasárnu a to takovou, že z formuláře všechny values předám rovnou repository a ono si samo vyfiltruje, které jsou pro něj (některé samozřejmě předtím upravím). proto tam mám ten výčet sloupců mysql tabulky.

Moje repozitory víceméně vychází z té co je začátečníkům prezentována v Quickstartu

Editoval danielseek (20. 11. 2013 1:37)