Model, fasáda, ORM čistý přístup

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

Mějme model, kde je 10 repositářů. A třeba pět komponent A, B, C, D, E. Řekněme, že tam není složitější bussiness logika a vše si obslouží ty komponenty samy (suchý CRUD), co zvládne $repository->save() a podobně.

Každá komponenta má 7 závislostí, ale zároveň žádná nemá stejné závislosti jako předchozí. Co je lepší přístup v Nette? Napadlo mě následující.

Místo současného stavu:

class ComponentA
{
	public function __construct(repo1, repo2, repo5, repo6, repo7, repo8, repo10)
	{}

	public function render()
	{
		$this->repo2()->exec();
	}
}

class ComponentB
{
	public function __construct(repo1, repo2, repo5, repo6, repo7, repo8, repo10)
	{}

	public function render()
	{
		$this->repo8()->exec();
	}
}

Udělat následující:

class ModuleModel
{
	public function __construct(repo1, repo2, ..., repo10)

	public function getRepo1()
	{
		return $this->repo1;
	}
}

class ComponentA
{
	public function __construct(ModuleModel)
	{}

	public function	render()
	{
		$this->ModuleModel->getRepo1()->exec();
	}
Barvoj
Člen | 60
+
0
-

Mě tedy připadá lepší ta první varianta. V tom druhém případě podle mě ta komponenta skrývá své závislosti. Jestli se nepletu říká se tomu service locator pattern.

Felix
Nette Core | 1247
+
0
-

Vetsinou kdyz maji moje komponenty vic jak 3 zavislosti na modelove vrstve, tak to vyclenuju do vlastniho mini-modelu (pokud je to fakt unikatni, tzn. skoro nikdy :-)), pripadne do fasade / service vrstvy.

Za me jsou dobre oba pristupy co tu ukazujes, pokud ModuleModule je mysleno jako fasada nad temi repo1…repoN. Pokud by to slouzilo jako linker, pripadne mini-container. Tak uz to hranici se ServiceLocatorem jak popisuje @Barvoj.

Barvoj
Člen | 60
+
0
-

pokud ModuleModule je mysleno jako fasada nad temi repo1…repoN

Mě právě připadá, že je to myšleno pouze jako „přepravka na repository“. Jelikož je tam getter, kterým si komponenta získá repository a nad ním pak volá nějakou metodu (v tomto případě exec())

Svaťa Šimara
Člen | 98
+
+3
-

Pokud mám tolik závislostí, zřejmě něco dělám špatně™.

A vskutku, pokud např. formulář obsahuje 7 selectboxů, může se ukázat, že jde po UX stránce nevhodně navržený formulář.

Co se v takových situacích dá dělat – odstínit kontext UI od modelu. A teď bohužel musím hodně abstraktně, protože neznám požadavky…

<?php
interface ModelAdapter {
	public function getOptionsA();
	public function getOptionsB();
	public function saveWholeForm(array $data);
}
?>

Tím zbyde pouze jedna závislost, která dělá pouze use-casy, které potřebujeme. Její implementace už bude mrcha závislá na 7 repozitářích.

Anebo nemusí, takovýto adaptér nemusí být osamocen, mohou být třeba 2. Komponenta bude závislá na 2 adaptérech, a každý z nich „jenom“ na menším počtu repozitářů.

Oli
Člen | 1215
+
0
-

Za mě ta 1. možnost. Zkoušel jsem i tu 2., ale blbě se mě s tím nakonec pracovalo.

@Fafin Muzes to trochu rozvest? Moc me neni jasny, jak se zbavis tech zavislosti, pokud tam mas treba 5× nějakej select, radio, checkboxlist nacitanej z db. Mohl bys poslat treba nejakou ukazku?

Svaťa Šimara
Člen | 98
+
0
-

@Oli Nezbavím, to jsem netvrdil.

Inu ukázka: https://drive.google.com/…bWJaZUU/view?…

Oli
Člen | 1215
+
0
-

@Fafin Díky za ukázku. Jsem tě nějak blbě pochopil, ta ukázka to dost objasnila :-) Líbí se mi to.

Pavel Kravčík
Člen | 1196
+
0
-

Díky za tipy.

To je právě to dilema, co zmínil Felix… Pokud by bylo deset modelů nebo deset obsáhlých repositářů. Asi by to měl být minicontainer na určité případy, kdy není potřeba nic dopisovat kromě závislosti repositáře. Tedy předpokládejme, že repositář umí základ CRUD fce (save, getBy, findBy, delete). Pokud by to měla být složitější logika, tak samozřejmě model s vlastním API.

Jasně, že formulář se sedmi závilostmi nemusí být dobře navržen. Je to jen teoretický příklad.

newPOPE
Člen | 648
+
0
-

To co popisuje @Fafin skor vyzera na ViewModel pattern. To je presne nieco co ti zakryje tych 7 zavislosti „repos“ a pripravuje data pre view (co moze byt UI, Xml, JSON, …)