5 vrstvovy model – facade VS repository

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

Ahojte, 2 dni studujem 5 vrstvovy model (Entity, Facade, Service, Repositary, Entity Manager).

Mam rozpisanu aplikaciu od ineho programatora s vyuzitim Kdyby\Doctrine a strasne ma pletie ako je to oddelene tam.. mam s toho strasny hokej, a neviem ci tomu nerozumiem alebo je to naprogramovane nespravne..

napr. fasada a vnej podobne metody:

	public function findByCategory(Category $category)
	{
		$qb = $this->dao->createQueryBuilder('article')
				->addOrderBy('article.created', 'DESC');
		$categories = $this->dao->related('categories')->children($category);
		$categories[] = $category;
		$criteria['article.categories.id'] = $categories;
		$qb->whereCriteria($criteria);
		return new ResultSet($qb->getQuery());
	}

nemalo by to byt v nejakom repozitari a vo fasade si len zavolat repozitar->findByCategory ? Chapem to spravne?

Filip Procházka
Moderator | 4668
+
0
-

Repozitáře bys právě dědit neměl, jenom proto abys do nich přidával další metody. Takové metody patří buď do services/facades nebo do QueryObjectů, ale né do repozitářů :)

marioff
Člen | 69
+
0
-

cize na repozitare sa vykaslat a rovno takto vyberat data priamo vo fasade (resp. v services) .. neviem, mam v tom uz riadny hokej, podla tych clankov som to pochopil tak ze najlepsie je vybrat data vo fasade napr.:

public function bestArticlesInCategory(Category $category)
{
	$articles = $this->repository->findByCategory($category);
	tu este nieco urobim s $articles...
	return $articles;
}

a ked budem potrebovat v inej fasade ziskat $articles tak znova skopirujem tu metodu do dalsej fasady? alebo ju urobit v services a odtial to potom len tahat vo fasadach?

lebo som bol v tom, ze toto riesi repozitar :(

Šaman
Člen | 2666
+
+2
-

Repozitář + DAO by ti měly tvořit nízkoúrovňovou vrstvu dotazů do db. Všechno by mělo komunikovat s databází přes ně (nebo přes něj, já to mám taky dohromady v jedné třídě).

Fasáda je pro vyšší logiku, právě třeba bestArticlesInCategory. V této metodě bys měl ale pracovat jen s metodami repozitářů ArticleRepository, případně i CategoryRepository, ale už ne se samotnou db. V Doctrine nedělám, takže ti neporadím konkrétní efektivní postup. V jednoduchém modelu bych to udělal asi takto:

<?php
public function bestArticlesInCategory(int $categoryId, int $count = 1)
{
    $articles = $this->articleRepository->findByCategory($categoryId)->orderBy('rating DESC')->limit($count);
    // případně si vrátíš všechny articles v dané kategorii a nějak je tu teď profiltruješ
    return $articles;
}
?>

P.S. Je dobré mít konzistentní názvy metod. Aby bylo jasné, co ti bestArticlesInCategory vrátí. Já bych si v ukázce třeba nechal vracet NDb\Selection a pak by se metoda jmenovala findBestArticlesInCategory, ale pokud by se celá fasáda jmenovala třeba ArticleService, pak bych to zkrátil na findBestInCategory, že hledám články je jasné z použité fasády. Pokud chci vracet jediný záznam (NDb\Row), pak by metoda začínala na get. Je na tobě, jakou konvenci si zavedeš, ale pak ji dodržuj.


P.P.S. Asi jsem nezdůraznil jednu věc – fasáda nikdy nedědí repozitáře, ta obaluje repozitáře! Používá kompozici (skládání), nikoliv dědičnost.
Tedy si je nechá injectnout.

Editoval Šaman (29. 12. 2014 18:15)

marioff
Člen | 69
+
0
-

ano, presne takto nejak som to myslel, ze repozitar bude zabezpecovat data pre fasadu a ta ich bud vrati presenteru, alebo ich este nejak doplni ci prefiltruje (napr. pomocou services).. len momentalne je aplikacia v takom stave, ze data sa vyberaju rovno vo fasade ako je v prvom prispevku.. preto som nevedel ci je to OK, alebo som nepochopil ten 5 vrstvovy model..

Šaman
Člen | 2666
+
+1
-

No, tady asi budeš potřebovat zkušeného Doctrináře, protože ty v té první ukázce nepracuješ přímo s databází (to by bylo špatně), ale ani nevyužíváš konkrétní repozitář/DAO, jak popisuje 5ti vrstvý model. Ty využíváš queryBuilder nad nějak doctrinou automaticky vytvořeném dao, takže ten první příspěvek IMHO 5ti vrstvý model obchází a používá jiné principy.

To, co jsem popisoval já, je obecný model, v Doctrine můžeš jednu věc udělat několika způsoby (a ten co používáš ty, je nejjednodušší – jen asi schovává to rozvrstvení).

marioff
Člen | 69
+
0
-

jj islo mi o to, ze sa vo fasade vyberaju data (uz nehra ulohu ci cez DAO – ja som to neprogramoval, skor sa natom ucim nette) , len mi to strasne nesedelo, uz len pri pomysleni, co ak budem podobne data potrebovat aj inde.. ale pochopili sme sa, dakujem za navedenie spravnym smerom

Šaman
Člen | 2666
+
+1
-

Jo, rozumíme si. To je přesně ten problém tohoto, nejjednoduššího řešení. Taky jsem na to už narazil v několika projektech, proto zatím Doctrinu nemám moc rád. Asi to jde udělat u dobře, ale taky dovolí prasit.

Problém nastane ve chvíli, kdy budeš chtít na úrovni repozitáře omezit třeba, že za platné članky se považují jen takové, které mají $deleted = FALSE. Ve tvém projektu to znamená projít všechny repozitáře a fasády (a raději i presentery) a dopsat to ručně. Pokud za přístup ke článkům zodpovídá jen ArticleRepository, tak projdeš jen ten. A v mém řešení se doplní jen metoda $articleRepository->findAll(), která vrací Selection, nad kterém probíhají všechny další operace s články.

marioff
Člen | 69
+
0
-

tak tak, upravy v buducnosti by boli peklo, prave preto musim cely model prerobit az potom pokracovat dalej, tak hadam som si vybral dobru architekturu modelu :D

Filip Procházka
Moderator | 4668
+
+3
-

FYI @Šaman, v doctrine existuje koncept filtrů, který umí automaticky do vytvářených dotazů přidávat podmínky. Napíšu tedy třeba SoftDeleteFilter, který mi vygeneruje něco jako AND e.deleted = FALSE a to se přidá jako podmínka do všech dotazů co vytahují data. Navíc si to můžu na frontendu zapnout a v administraci vypnout podle potřeby, takže se pak ke smazaným snadno dostanu :)

A prasit se dá ve všem :)

marioff
Člen | 69
+
0
-

Filip: ano , toto dokonca aj pouzivam na blokovanych uzivatelov, resp. neaktivne clanky atd… velmi sikovne :)

Prado
Člen | 21
+
0
-

Já se fasádu snažím používat jako rozhraní mezi modelem a kontrolerem. Je to pro mě něco, odkud když odříznu model a reimplementuji ho, tak to zbytek aplikace nepozná. Z lenosti mám fasádu většinou jednu, ale v zásadě jich může být více podle řešené domény. Sice to nikdy nedodržím, ale v zásadě mám takovou představu, že obsahuje jen minimum logiky a spíše to ověří práva, ohlídají transakci a volají metody ze servisy nebo repository. Fasáda u mne vrací entity, takže z kontroleru mohu volat i jejich metody, ale chápal bych i transformaci do DTO.

Servisní třídy u mne zahrnují vyšší logiku. Injektují se do nich repository i jiné servisy, podle potřeby. Od fasády se u mne liší tím, že neřeší transakce nebo práva: co dostanou za úkol, to provedou nebo vyhodí výjimku.

Někdy mám ještě utility. To jsou zcela bezstavové třídy, takové knihovny funkcí. Obvykle zjistím, že to samé již někdo naimplementoval lépe a měl jsem využít jeho práci.

Repository pro mne vrací datové kolekce podle kritérií, takže výběr článků podle kategorie bych dal rozhodně tam. Nebo pokud používáte query objekt do servisní vrstvy.